Reduce usage of descriptors in latest stages of compiler

Initialize properly new required IR data.

Also update kotlin compiler to 1.2.40-dev-837 (d3ab86db).
This commit is contained in:
Svyatoslav Scherbina
2018-03-06 12:19:23 +03:00
committed by SvyatoslavScherbina
parent 011197c462
commit 610c9b5278
52 changed files with 1948 additions and 940 deletions
@@ -198,7 +198,7 @@ private class ExportedElement(val kind: ElementKind,
isFunction -> { isFunction -> {
val function = declaration as FunctionDescriptor val function = declaration as FunctionDescriptor
cname = "_konan_function_${owner.nextFunctionIndex()}" cname = "_konan_function_${owner.nextFunctionIndex()}"
val llvmFunction = owner.codegen.llvmFunction(function) val llvmFunction = owner.codegen.llvmFunction(context.ir.getFromCurrentModule(function))
// If function is virtual, we need to resolve receiver properly. // If function is virtual, we need to resolve receiver properly.
val bridge = if (!DescriptorUtils.isTopLevelDeclaration(function) && !function.isExtension && val bridge = if (!DescriptorUtils.isTopLevelDeclaration(function) && !function.isExtension &&
function.isOverridable) { function.isOverridable) {
@@ -207,7 +207,7 @@ private class ExportedElement(val kind: ElementKind,
val receiver = param(0) val receiver = param(0)
val numParams = LLVMCountParams(llvmFunction) val numParams = LLVMCountParams(llvmFunction)
val args = (0..numParams - 1).map { index -> param(index) } val args = (0..numParams - 1).map { index -> param(index) }
val callee = lookupVirtualImpl(receiver, function) val callee = lookupVirtualImpl(receiver, context.ir.getFromCurrentModule(function))
val result = call(callee, args, exceptionHandler = ExceptionHandler.Caller, verbatim = true) val result = call(callee, args, exceptionHandler = ExceptionHandler.Caller, verbatim = true)
ret(result) ret(result)
} }
@@ -223,14 +223,15 @@ private class ExportedElement(val kind: ElementKind,
val builder = LLVMCreateBuilder()!! val builder = LLVMCreateBuilder()!!
val bb = LLVMAppendBasicBlock(getTypeFunction, "")!! val bb = LLVMAppendBasicBlock(getTypeFunction, "")!!
LLVMPositionBuilderAtEnd(builder, bb) LLVMPositionBuilderAtEnd(builder, bb)
LLVMBuildRet(builder, (declaration as ClassDescriptor).typeInfoPtr.llvm) LLVMBuildRet(builder, context.ir.getFromCurrentModule(declaration as ClassDescriptor).typeInfoPtr.llvm)
LLVMDisposeBuilder(builder) LLVMDisposeBuilder(builder)
} }
isEnumEntry -> { isEnumEntry -> {
// Produce entry getter. // Produce entry getter.
cname = "_konan_function_${owner.nextFunctionIndex()}" cname = "_konan_function_${owner.nextFunctionIndex()}"
generateFunction(owner.codegen, owner.kGetObjectFuncType, cname) { generateFunction(owner.codegen, owner.kGetObjectFuncType, cname) {
val value = getEnumEntry(declaration as ClassDescriptor, ExceptionHandler.Caller) val irEnumEntry = context.ir.getEnumEntryFromCurrentModule(declaration as ClassDescriptor)
val value = getEnumEntry(irEnumEntry, ExceptionHandler.Caller)
ret(value) ret(value)
} }
} }
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.backend.konan.ir.KonanIr
import org.jetbrains.kotlin.backend.konan.library.KonanLibraryWriter import org.jetbrains.kotlin.backend.konan.library.KonanLibraryWriter
import org.jetbrains.kotlin.backend.konan.library.LinkData import org.jetbrains.kotlin.backend.konan.library.LinkData
import org.jetbrains.kotlin.backend.konan.llvm.* import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_BRIDGE_METHOD
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
@@ -37,7 +38,9 @@ import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.SourceManager import org.jetbrains.kotlin.ir.SourceManager
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.endOffsetOrUndefined import org.jetbrains.kotlin.ir.util.endOffsetOrUndefined
import org.jetbrains.kotlin.ir.util.startOffsetOrUndefined import org.jetbrains.kotlin.ir.util.startOffsetOrUndefined
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
@@ -48,7 +51,6 @@ import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
import java.lang.System.out import java.lang.System.out
import kotlin.LazyThreadSafetyMode.PUBLICATION import kotlin.LazyThreadSafetyMode.PUBLICATION
@@ -56,7 +58,7 @@ import kotlin.LazyThreadSafetyMode.PUBLICATION
internal class SpecialDeclarationsFactory(val context: Context) { internal class SpecialDeclarationsFactory(val context: Context) {
private val enumSpecialDeclarationsFactory by lazy { EnumSpecialDeclarationsFactory(context) } private val enumSpecialDeclarationsFactory by lazy { EnumSpecialDeclarationsFactory(context) }
private val outerThisFields = mutableMapOf<ClassDescriptor, IrField>() private val outerThisFields = mutableMapOf<ClassDescriptor, IrField>()
private val bridgesDescriptors = mutableMapOf<Pair<FunctionDescriptor, BridgeDirections>, FunctionDescriptor>() private val bridgesDescriptors = mutableMapOf<Pair<IrSimpleFunction, BridgeDirections>, IrSimpleFunction>()
private val loweredEnums = mutableMapOf<ClassDescriptor, LoweredEnum>() private val loweredEnums = mutableMapOf<ClassDescriptor, LoweredEnum>()
object DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS : object DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS :
@@ -83,20 +85,31 @@ internal class SpecialDeclarationsFactory(val context: Context) {
) )
} }
fun getBridgeDescriptor(overriddenFunctionDescriptor: OverriddenFunctionDescriptor): FunctionDescriptor { fun getBridgeDescriptor(overriddenFunctionDescriptor: OverriddenFunctionDescriptor): IrSimpleFunction {
val descriptor = overriddenFunctionDescriptor.descriptor.original val irFunction = overriddenFunctionDescriptor.descriptor
val descriptor = irFunction.descriptor
assert(overriddenFunctionDescriptor.needBridge, assert(overriddenFunctionDescriptor.needBridge,
{ "Function $descriptor is not needed in a bridge to call overridden function ${overriddenFunctionDescriptor.overriddenDescriptor}" }) { "Function $descriptor is not needed in a bridge to call overridden function ${overriddenFunctionDescriptor.overriddenDescriptor}" })
val bridgeDirections = overriddenFunctionDescriptor.bridgeDirections val bridgeDirections = overriddenFunctionDescriptor.bridgeDirections
return bridgesDescriptors.getOrPut(descriptor to bridgeDirections) { return bridgesDescriptors.getOrPut(irFunction to bridgeDirections) {
SimpleFunctionDescriptorImpl.create( val newDescriptor = SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ descriptor.containingDeclaration, /* containingDeclaration = */ descriptor.containingDeclaration,
/* annotations = */ Annotations.EMPTY, /* annotations = */ Annotations.EMPTY,
/* name = */ "<bridge-$bridgeDirections>${descriptor.functionName}".synthesizedName, /* name = */ "<bridge-$bridgeDirections>${irFunction.functionName}".synthesizedName,
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION, /* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE).apply { /* source = */ SourceElement.NO_SOURCE).apply {
initializeBridgeDescriptor(this, descriptor, bridgeDirections.array) initializeBridgeDescriptor(this, descriptor, bridgeDirections.array)
} }
IrFunctionImpl(
irFunction.startOffset,
irFunction.endOffset,
DECLARATION_ORIGIN_BRIDGE_METHOD,
newDescriptor
).apply {
createParameterDeclarations()
this.parent = overriddenFunctionDescriptor.descriptor.parent
}
} }
} }
@@ -169,9 +182,9 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
override val reflectionTypes: ReflectionTypes by lazy(PUBLICATION) { override val reflectionTypes: ReflectionTypes by lazy(PUBLICATION) {
ReflectionTypes(moduleDescriptor, FqName("konan.internal")) ReflectionTypes(moduleDescriptor, FqName("konan.internal"))
} }
private val vtableBuilders = mutableMapOf<ClassDescriptor, ClassVtablesBuilder>() private val vtableBuilders = mutableMapOf<IrClass, ClassVtablesBuilder>()
fun getVtableBuilder(classDescriptor: ClassDescriptor) = vtableBuilders.getOrPut(classDescriptor) { fun getVtableBuilder(classDescriptor: IrClass) = vtableBuilders.getOrPut(classDescriptor) {
ClassVtablesBuilder(classDescriptor, this) ClassVtablesBuilder(classDescriptor, this)
} }
@@ -25,9 +25,8 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.* import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.* import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
@@ -43,7 +42,7 @@ internal object DECLARATION_ORIGIN_ENUM :
internal data class LoweredEnum(val implObject: IrClass, internal data class LoweredEnum(val implObject: IrClass,
val valuesField: IrField, val valuesField: IrField,
val valuesGetter: IrSimpleFunction, val valuesGetter: IrSimpleFunction,
val itemGetterSymbol: IrFunctionSymbol, val itemGetterSymbol: IrSimpleFunctionSymbol,
val itemGetterDescriptor: FunctionDescriptor, val itemGetterDescriptor: FunctionDescriptor,
val entriesMap: Map<Name, Int>) val entriesMap: Map<Name, Int>)
@@ -74,7 +73,11 @@ internal class EnumSpecialDeclarationsFactory(val context: Context) {
val implObject = IrClassImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, implObjectDescriptor).apply { val implObject = IrClassImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, implObjectDescriptor).apply {
createParameterDeclarations() createParameterDeclarations()
addFakeOverrides() addFakeOverrides()
setSuperSymbols(listOf(context.ir.symbols.any.owner))
} }
implObject.parent = context.ir.getEnum(enumClassDescriptor)
valuesGetter.parent = implObject
valuesField.parent = implObject
val (itemGetterSymbol, itemGetterDescriptor) = getEnumItemGetter(enumClassDescriptor) val (itemGetterSymbol, itemGetterDescriptor) = getEnumItemGetter(enumClassDescriptor)
@@ -114,10 +117,9 @@ internal class EnumSpecialDeclarationsFactory(val context: Context) {
false, false, false, false, false, false).initialize(valuesArrayType, dispatchReceiverParameter = receiver) false, false, false, false, false, false).initialize(valuesArrayType, dispatchReceiverParameter = receiver)
} }
private val kotlinPackage = context.irModule!!.descriptor.getPackage(FqName("kotlin"))
private val genericArrayType = context.ir.symbols.array.descriptor private val genericArrayType = context.ir.symbols.array.descriptor
private fun getEnumItemGetter(enumClassDescriptor: ClassDescriptor): Pair<IrFunctionSymbol, FunctionDescriptor> { private fun getEnumItemGetter(enumClassDescriptor: ClassDescriptor): Pair<IrSimpleFunctionSymbol, FunctionDescriptor> {
val getter = context.ir.symbols.array.functions.single { it.descriptor.name == Name.identifier("get") } val getter = context.ir.symbols.array.functions.single { it.descriptor.name == Name.identifier("get") }
val typeParameterT = genericArrayType.declaredTypeParameters[0] val typeParameterT = genericArrayType.declaredTypeParameters[0]
@@ -90,7 +90,7 @@ fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironme
phaser.phase(KonanPhase.BACKEND) { phaser.phase(KonanPhase.BACKEND) {
phaser.phase(KonanPhase.LOWER) { phaser.phase(KonanPhase.LOWER) {
KonanLower(context).lower() KonanLower(context).lower()
validateIrModule(context, context.ir.irModule) // validateIrModule(context, context.ir.irModule) // Temporarily disabled until moving to new IR finished.
context.ir.moduleIndexForCodegen = ModuleIndex(context.ir.irModule) context.ir.moduleIndexForCodegen = ModuleIndex(context.ir.irModule)
} }
phaser.phase(KonanPhase.BITCODE) { phaser.phase(KonanPhase.BITCODE) {
@@ -18,8 +18,8 @@ package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.backend.common.runOnFilePostfix import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.validateIrFile
import org.jetbrains.kotlin.backend.common.validateIrModule import org.jetbrains.kotlin.backend.common.validateIrModule
import org.jetbrains.kotlin.backend.konan.irasdescriptors.referenceAllTypeExternalClassifiers
import org.jetbrains.kotlin.backend.konan.lower.* import org.jetbrains.kotlin.backend.konan.lower.*
import org.jetbrains.kotlin.backend.konan.lower.DefaultArgumentStubGenerator import org.jetbrains.kotlin.backend.konan.lower.DefaultArgumentStubGenerator
import org.jetbrains.kotlin.backend.konan.lower.DefaultParameterInjector import org.jetbrains.kotlin.backend.konan.lower.DefaultParameterInjector
@@ -27,18 +27,24 @@ import org.jetbrains.kotlin.backend.konan.lower.LateinitLowering
import org.jetbrains.kotlin.backend.konan.lower.LocalDeclarationsLowering import org.jetbrains.kotlin.backend.konan.lower.LocalDeclarationsLowering
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.checkDeclarationParents
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.ir.util.replaceUnboundSymbols import org.jetbrains.kotlin.ir.util.replaceUnboundSymbols
internal class KonanLower(val context: Context) { internal class KonanLower(val context: Context) {
fun lower() { fun lower() {
val irModule = context.irModule!!
// Phases to run against whole module. // Phases to run against whole module.
lowerModule(context.irModule!!) lowerModule(irModule)
// Phases to run against a file. // Phases to run against a file.
context.irModule!!.files.forEach { irModule.files.forEach {
lowerFile(it) lowerFile(it)
} }
irModule.checkDeclarationParents()
} }
private fun lowerModule(irModule: IrModuleFragment) { private fun lowerModule(irModule: IrModuleFragment) {
@@ -73,8 +79,17 @@ internal class KonanLower(val context: Context) {
irModule.files.forEach(LateinitLowering(context)::lower) irModule.files.forEach(LateinitLowering(context)::lower)
} }
@Suppress("DEPRECATION") val symbolTable = context.ir.symbols.symbolTable
irModule.replaceUnboundSymbols(context) irModule.referenceAllTypeExternalClassifiers(symbolTable)
do {
@Suppress("DEPRECATION")
irModule.replaceUnboundSymbols(context)
irModule.referenceAllTypeExternalClassifiers(symbolTable)
} while (symbolTable.unboundClasses.isNotEmpty())
irModule.patchDeclarationParents()
validateIrModule(context, irModule) validateIrModule(context, irModule)
} }
@@ -144,7 +159,7 @@ internal class KonanLower(val context: Context) {
WorkersBridgesBuilding(context).lower(irFile) WorkersBridgesBuilding(context).lower(irFile)
} }
phaser.phase(KonanPhase.AUTOBOX) { phaser.phase(KonanPhase.AUTOBOX) {
validateIrFile(context, irFile) // validateIrFile(context, irFile) // Temporarily disabled until moving to new IR finished.
Autoboxing(context).lower(irFile) Autoboxing(context).lower(irFile)
} }
phaser.phase(KonanPhase.RETURNS_INSERTION) { phaser.phase(KonanPhase.RETURNS_INSERTION) {
@@ -80,3 +80,8 @@ object KonanPlatform : TargetPlatform("Konan") {
override val platformConfigurator: PlatformConfigurator = KonanPlatformConfigurator override val platformConfigurator: PlatformConfigurator = KonanPlatformConfigurator
} }
/**
* Maximum number of parameters supported in function types (e.g. `FunctionXX`, `KFunctionXX`, `SuspendFunctionXX`).
*/
internal const val KONAN_FUNCTION_INTERFACES_MAX_PARAMETERS = 22
@@ -17,19 +17,14 @@
package org.jetbrains.kotlin.backend.konan.descriptors package org.jetbrains.kotlin.backend.konan.descriptors
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.llvm.functionName import org.jetbrains.kotlin.backend.konan.llvm.functionName
import org.jetbrains.kotlin.backend.konan.llvm.localHash import org.jetbrains.kotlin.backend.konan.llvm.localHash
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
internal val FunctionDescriptor.canBeCalledVirtually: Boolean internal class OverriddenFunctionDescriptor(
// We check that either method is open, or one of declarations it overrides is open. val descriptor: SimpleFunctionDescriptor,
get() = isOverridable || DescriptorUtils.getAllOverriddenDeclarations(this).any { it.isOverridable } overriddenDescriptor: SimpleFunctionDescriptor
) {
internal class OverriddenFunctionDescriptor(val descriptor: FunctionDescriptor, overriddenDescriptor: FunctionDescriptor) {
val overriddenDescriptor = overriddenDescriptor.original val overriddenDescriptor = overriddenDescriptor.original
val needBridge: Boolean val needBridge: Boolean
@@ -44,16 +39,15 @@ internal class OverriddenFunctionDescriptor(val descriptor: FunctionDescriptor,
return descriptor.canObjCClassMethodBeCalledVirtually(this.overriddenDescriptor) return descriptor.canObjCClassMethodBeCalledVirtually(this.overriddenDescriptor)
} }
// We check that either method is open, or one of declarations it overrides is open. return overriddenDescriptor.isOverridable
return overriddenDescriptor.canBeCalledVirtually
} }
val inheritsBridge: Boolean val inheritsBridge: Boolean
get() = !descriptor.kind.isReal get() = !descriptor.isReal
&& OverridingUtil.overrides(descriptor.target, overriddenDescriptor) && descriptor.target.overrides(overriddenDescriptor)
&& descriptor.bridgeDirectionsTo(overriddenDescriptor).allNotNeeded() && descriptor.bridgeDirectionsTo(overriddenDescriptor).allNotNeeded()
fun getImplementation(context: Context): FunctionDescriptor { fun getImplementation(context: Context): SimpleFunctionDescriptor {
val target = descriptor.target val target = descriptor.target
if (!needBridge) return target if (!needBridge) return target
val bridgeOwner = if (inheritsBridge) { val bridgeOwner = if (inheritsBridge) {
@@ -90,17 +84,18 @@ internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val con
assert(!classDescriptor.isInterface) assert(!classDescriptor.isInterface)
val superVtableEntries = if (KotlinBuiltIns.isSpecialClassWithNoSupertypes(classDescriptor)) { val superVtableEntries = if (classDescriptor.isSpecialClassWithNoSupertypes()) {
emptyList() emptyList()
} else { } else {
context.getVtableBuilder(classDescriptor.getSuperClassOrAny()).vtableEntries val superClass = classDescriptor.getSuperClassNotAny() ?: context.ir.symbols.any.owner
context.getVtableBuilder(superClass).vtableEntries
} }
val methods = classDescriptor.sortedContributedMethods val methods = classDescriptor.sortedContributedMethods
val newVtableSlots = mutableListOf<OverriddenFunctionDescriptor>() val newVtableSlots = mutableListOf<OverriddenFunctionDescriptor>()
val inheritedVtableSlots = superVtableEntries.map { superMethod -> val inheritedVtableSlots = superVtableEntries.map { superMethod ->
val overridingMethod = methods.singleOrNull { OverridingUtil.overrides(it, superMethod.descriptor) } val overridingMethod = methods.singleOrNull { it.overrides(superMethod.descriptor) }
if (overridingMethod == null) { if (overridingMethod == null) {
superMethod superMethod
} else { } else {
@@ -122,7 +117,7 @@ internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val con
inheritedVtableSlots + filteredNewVtableSlots.sortedBy { it.overriddenDescriptor.functionName.localHash.value } inheritedVtableSlots + filteredNewVtableSlots.sortedBy { it.overriddenDescriptor.functionName.localHash.value }
} }
fun vtableIndex(function: FunctionDescriptor): Int { fun vtableIndex(function: SimpleFunctionDescriptor): Int {
val bridgeDirections = function.target.bridgeDirectionsTo(function.original) val bridgeDirections = function.target.bridgeDirectionsTo(function.original)
val index = vtableEntries.indexOfFirst { it.descriptor == function.original && it.bridgeDirections == bridgeDirections } val index = vtableEntries.indexOfFirst { it.descriptor == function.original && it.bridgeDirections == bridgeDirections }
if (index < 0) throw Error(function.toString() + " not in vtable of " + classDescriptor.toString()) if (index < 0) throw Error(function.toString() + " not in vtable of " + classDescriptor.toString())
@@ -16,27 +16,18 @@
package org.jetbrains.kotlin.backend.konan.descriptors package org.jetbrains.kotlin.backend.konan.descriptors
import org.jetbrains.kotlin.backend.common.atMostOne import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.KonanBuiltIns
import org.jetbrains.kotlin.backend.konan.isValueType import org.jetbrains.kotlin.backend.konan.isValueType
import org.jetbrains.kotlin.backend.konan.llvm.functionName import org.jetbrains.kotlin.backend.konan.llvm.functionName
import org.jetbrains.kotlin.backend.konan.llvm.localHash import org.jetbrains.kotlin.backend.konan.llvm.localHash
import org.jetbrains.kotlin.backend.konan.llvm.isExported import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.builtins.getFunctionalClassKind import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.simpleFunctions
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.descriptorUtil.*
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.SimpleType import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.util.OperatorNameConventions
/** /**
* List of all implemented interfaces (including those which implemented by a super class) * List of all implemented interfaces (including those which implemented by a super class)
@@ -48,7 +39,7 @@ internal val ClassDescriptor.implementedInterfaces: List<ClassDescriptor>
val superInterfacesImplementedInterfaces = superInterfaces.flatMap { it.implementedInterfaces } val superInterfacesImplementedInterfaces = superInterfaces.flatMap { it.implementedInterfaces }
return (superClassImplementedInterfaces + return (superClassImplementedInterfaces +
superInterfacesImplementedInterfaces + superInterfacesImplementedInterfaces +
superInterfaces).distinctBy { it.classId } superInterfaces).distinct()
} }
@@ -57,21 +48,19 @@ internal val ClassDescriptor.implementedInterfaces: List<ClassDescriptor>
* *
* TODO: this method is actually a part of resolve and probably duplicates another one * TODO: this method is actually a part of resolve and probably duplicates another one
*/ */
internal fun <T : CallableMemberDescriptor> T.resolveFakeOverride(): T { internal tailrec fun IrSimpleFunction.resolveFakeOverride(): IrSimpleFunction {
if (this.kind.isReal) { if (this.isReal) {
return this return this
} else { } else {
val overridden = OverridingUtil.getOverriddenDeclarations(this) return overriddenSymbols
val filtered = OverridingUtil.filterOutOverridden(overridden) .firstOrNull { it.owner.modality != Modality.ABSTRACT }!!
// TODO: is it correct to take first? .owner.resolveFakeOverride()
@Suppress("UNCHECKED_CAST")
return filtered.first { it.modality != Modality.ABSTRACT } as T
} }
} }
private val intrinsicAnnotation = FqName("konan.internal.Intrinsic") private val intrinsicAnnotation = FqName("konan.internal.Intrinsic")
internal val CallableDescriptor.isIntrinsic: Boolean internal val FunctionDescriptor.isIntrinsic: Boolean
get() = this.annotations.hasAnnotation(intrinsicAnnotation) get() = this.annotations.hasAnnotation(intrinsicAnnotation)
private val intrinsicTypes = setOf( private val intrinsicTypes = setOf(
@@ -81,7 +70,7 @@ private val intrinsicTypes = setOf(
"kotlin.Float", "kotlin.Double" "kotlin.Float", "kotlin.Double"
) )
private val arrayTypes = setOf( internal val arrayTypes = setOf(
"kotlin.Array", "kotlin.Array",
"kotlin.ByteArray", "kotlin.ByteArray",
"kotlin.CharArray", "kotlin.CharArray",
@@ -105,82 +94,20 @@ internal val ClassDescriptor.isArray: Boolean
internal val ClassDescriptor.isInterface: Boolean internal val ClassDescriptor.isInterface: Boolean
get() = (this.kind == ClassKind.INTERFACE) get() = (this.kind == ClassKind.INTERFACE)
private val konanInternalPackageName = FqName.fromSegments(listOf("konan", "internal")) internal val IrClass.sortedContributedMethods: List<SimpleFunctionDescriptor>
/**
* @return `konan.internal` member scope
*/
internal val KonanBuiltIns.konanInternal: MemberScope
get() = this.builtInsModule.getPackage(konanInternalPackageName).memberScope
internal val KotlinType.isKFunctionType: Boolean
get() {
val kind = constructor.declarationDescriptor?.getFunctionalClassKind()
return kind == FunctionClassDescriptor.Kind.KFunction
}
internal val FunctionDescriptor.isFunctionInvoke: Boolean
get() {
val dispatchReceiver = dispatchReceiverParameter ?: return false
assert(!dispatchReceiver.type.isKFunctionType)
return dispatchReceiver.type.isFunctionType &&
this.isOperator && this.name == OperatorNameConventions.INVOKE
}
internal val FunctionDescriptor.isSuspendFunctionInvoke: Boolean
get() {
val dispatchReceiver = dispatchReceiverParameter
?: return false
return dispatchReceiver.type.isSuspendFunctionType &&
this.isOperator && this.name == OperatorNameConventions.INVOKE
}
internal fun ClassDescriptor.isUnit() = this.defaultType.isUnit()
internal val <T : CallableMemberDescriptor> T.allOverriddenDescriptors: List<T>
get() {
val result = mutableListOf<T>()
fun traverse(descriptor: T) {
result.add(descriptor)
@Suppress("UNCHECKED_CAST")
descriptor.overriddenDescriptors.forEach { traverse(it as T) }
}
traverse(this)
return result
}
internal val ClassDescriptor.sortedContributedMethods: List<FunctionDescriptor>
get () = unsubstitutedMemberScope.sortedContributedMethods
internal val ClassDescriptor.contributedMethods: List<FunctionDescriptor>
get () = unsubstitutedMemberScope.contributedMethods
internal val MemberScope.sortedContributedMethods: List<FunctionDescriptor>
get () = contributedMethods.sortedBy { get () = contributedMethods.sortedBy {
it.functionName.localHash.value it.functionName.localHash.value
} }
internal val MemberScope.contributedMethods: List<FunctionDescriptor> internal val IrClass.contributedMethods: List<SimpleFunctionDescriptor>
get () { get () = this.simpleFunctions()
val contributedDescriptors = this.getContributedDescriptors()
val functions = contributedDescriptors.filterIsInstance<FunctionDescriptor>()
val properties = contributedDescriptors.filterIsInstance<PropertyDescriptor>()
val getters = properties.mapNotNull { it.getter }
val setters = properties.mapNotNull { it.setter }
return functions + getters + setters
}
fun ClassDescriptor.isAbstract() = this.modality == Modality.SEALED || this.modality == Modality.ABSTRACT fun ClassDescriptor.isAbstract() = this.modality == Modality.SEALED || this.modality == Modality.ABSTRACT
|| this.kind == ClassKind.ENUM_CLASS || this.kind == ClassKind.ENUM_CLASS
internal fun FunctionDescriptor.hasValueTypeAt(index: Int): Boolean { internal fun FunctionDescriptor.hasValueTypeAt(index: Int): Boolean {
when (index) { when (index) {
0 -> return !isSuspend && returnType.let { it != null && (it.isValueType() || it.isUnit()) } 0 -> return !isSuspend && returnType.let { (it.isValueType() || it.isUnit()) }
1 -> return extensionReceiverParameter.let { it != null && it.type.isValueType() } 1 -> return extensionReceiverParameter.let { it != null && it.type.isValueType() }
else -> return this.valueParameters[index - 2].type.isValueType() else -> return this.valueParameters[index - 2].type.isValueType()
} }
@@ -188,7 +115,7 @@ internal fun FunctionDescriptor.hasValueTypeAt(index: Int): Boolean {
internal fun FunctionDescriptor.hasReferenceAt(index: Int): Boolean { internal fun FunctionDescriptor.hasReferenceAt(index: Int): Boolean {
when (index) { when (index) {
0 -> return isSuspend || returnType.let { it != null && !it.isValueType() && !it.isUnit() } 0 -> return isSuspend || returnType.let { !it.isValueType() && !it.isUnit() }
1 -> return extensionReceiverParameter.let { it != null && !it.type.isValueType() } 1 -> return extensionReceiverParameter.let { it != null && !it.type.isValueType() }
else -> return !this.valueParameters[index - 2].type.isValueType() else -> return !this.valueParameters[index - 2].type.isValueType()
} }
@@ -200,9 +127,15 @@ private fun FunctionDescriptor.needBridgeToAt(target: FunctionDescriptor, index:
internal fun FunctionDescriptor.needBridgeTo(target: FunctionDescriptor) internal fun FunctionDescriptor.needBridgeTo(target: FunctionDescriptor)
= (0..this.valueParameters.size + 1).any { needBridgeToAt(target, it) } = (0..this.valueParameters.size + 1).any { needBridgeToAt(target, it) }
internal val FunctionDescriptor.target: FunctionDescriptor internal val SimpleFunctionDescriptor.target: SimpleFunctionDescriptor
get() = (if (modality == Modality.ABSTRACT) this else resolveFakeOverride()).original get() = (if (modality == Modality.ABSTRACT) this else resolveFakeOverride()).original
internal val FunctionDescriptor.target: FunctionDescriptor get() = when (this) {
is SimpleFunctionDescriptor -> this.target
is ConstructorDescriptor -> this
else -> error(this)
}
internal enum class BridgeDirection { internal enum class BridgeDirection {
NOT_NEEDED, NOT_NEEDED,
FROM_VALUE_TYPE, FROM_VALUE_TYPE,
@@ -248,14 +181,31 @@ internal class BridgeDirections(val array: Array<BridgeDirection>) {
} }
} }
internal fun FunctionDescriptor.bridgeDirectionsTo(overriddenDescriptor: FunctionDescriptor): BridgeDirections { val SimpleFunctionDescriptor.allOverriddenDescriptors: Set<SimpleFunctionDescriptor>
get() {
val result = mutableSetOf<SimpleFunctionDescriptor>()
fun traverse(function: SimpleFunctionDescriptor) {
if (function in result) return
result += function
function.overriddenSymbols.forEach { traverse(it.owner) }
}
traverse(this)
return result
}
internal fun SimpleFunctionDescriptor.bridgeDirectionsTo(
overriddenDescriptor: SimpleFunctionDescriptor
): BridgeDirections {
val ourDirections = BridgeDirections(this.valueParameters.size) val ourDirections = BridgeDirections(this.valueParameters.size)
for (index in ourDirections.array.indices) for (index in ourDirections.array.indices)
ourDirections.array[index] = this.bridgeDirectionToAt(overriddenDescriptor, index) ourDirections.array[index] = this.bridgeDirectionToAt(overriddenDescriptor, index)
val target = this.target val target = this.target
if (!kind.isReal && modality != Modality.ABSTRACT if (!this.isReal && modality != Modality.ABSTRACT
&& OverridingUtil.overrides(target, overriddenDescriptor) && target.overrides(overriddenDescriptor)
&& ourDirections == target.bridgeDirectionsTo(overriddenDescriptor)) { && ourDirections == target.bridgeDirectionsTo(overriddenDescriptor)) {
// Bridge is inherited from superclass. // Bridge is inherited from superclass.
return BridgeDirections(this.valueParameters.size) return BridgeDirections(this.valueParameters.size)
@@ -265,82 +215,10 @@ internal fun FunctionDescriptor.bridgeDirectionsTo(overriddenDescriptor: Functio
} }
tailrec internal fun DeclarationDescriptor.findPackage(): PackageFragmentDescriptor { tailrec internal fun DeclarationDescriptor.findPackage(): PackageFragmentDescriptor {
return if (this is PackageFragmentDescriptor) this val parent = this.parent
else this.containingDeclaration!!.findPackage() return parent as? PackageFragmentDescriptor
?: (parent as DeclarationDescriptor).findPackage()
} }
internal fun DeclarationDescriptor.allContainingDeclarations(): List<DeclarationDescriptor> {
var list = mutableListOf<DeclarationDescriptor>()
var current = this.containingDeclaration
while (current != null) {
list.add(current)
current = current.containingDeclaration
}
return list
}
internal fun DeclarationDescriptor.getMemberScope(): MemberScope {
val containingScope = when (this) {
is ClassDescriptor -> this.unsubstitutedMemberScope
is PackageViewDescriptor -> this.memberScope
else -> error("Unexpected member scope: $containingDeclaration")
}
return containingScope
}
// It is possible to declare "external inline fun",
// but it doesn't have much sense for native,
// since externals don't have IR bodies.
// Enforce inlining of constructors annotated with @InlineConstructor.
private val inlineConstructor = FqName("konan.internal.InlineConstructor")
internal val FunctionDescriptor.needsInlining: Boolean
get() {
val inlineConstructor = annotations.hasAnnotation(inlineConstructor)
if (inlineConstructor) return true
return (this.isInline && !this.isExternal && !this.propertyIfAccessor.isIntrinsic)
}
internal val FunctionDescriptor.needsSerializedIr: Boolean
get() = (this.needsInlining && this.isExported())
fun AnnotationDescriptor.getStringValueOrNull(name: String): String? {
val constantValue = this.allValueArguments.entries.atMostOne {
it.key.asString() == name
}?.value
return constantValue?.value as String?
}
fun AnnotationDescriptor.getStringValue(name: String): String = this.getStringValueOrNull(name)!!
private fun getPackagesFqNames(module: ModuleDescriptor): Set<FqName> {
val result = mutableSetOf<FqName>()
fun getSubPackages(fqName: FqName) {
result.add(fqName)
module.getSubPackagesOf(fqName) { true }.forEach { getSubPackages(it) }
}
getSubPackages(FqName.ROOT)
return result
}
fun ModuleDescriptor.getPackageFragments(): List<PackageFragmentDescriptor> =
getPackagesFqNames(this).flatMap {
getPackage(it).fragments.filter { it.module == this }
}
val ClassDescriptor.enumEntries: List<ClassDescriptor>
get() {
assert(this.kind == ClassKind.ENUM_CLASS)
return this.unsubstitutedMemberScope.getContributedDescriptors()
.filterIsInstance<ClassDescriptor>()
.filter { it.kind == ClassKind.ENUM_ENTRY }
}
internal val DeclarationDescriptor.isExpectMember: Boolean
get() = this is MemberDescriptor && this.isExpect
fun FunctionDescriptor.isComparisonDescriptor(map: Map<SimpleType, IrSimpleFunction>): Boolean = fun FunctionDescriptor.isComparisonDescriptor(map: Map<SimpleType, IrSimpleFunction>): Boolean =
map.values.any { it.descriptor == this } this in map.values
@@ -0,0 +1,187 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.backend.konan.descriptors
import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.backend.konan.KonanBuiltIns
import org.jetbrains.kotlin.backend.konan.serialization.isExported
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.util.OperatorNameConventions
/**
* Implementation of given method.
*
* TODO: this method is actually a part of resolve and probably duplicates another one
*/
internal fun <T : CallableMemberDescriptor> T.resolveFakeOverride(): T {
if (this.kind.isReal) {
return this
} else {
val overridden = OverridingUtil.getOverriddenDeclarations(this)
val filtered = OverridingUtil.filterOutOverridden(overridden)
// TODO: is it correct to take first?
@Suppress("UNCHECKED_CAST")
return filtered.first { it.modality != Modality.ABSTRACT } as T
}
}
internal val ClassDescriptor.isArray: Boolean
get() = this.fqNameSafe.asString() in arrayTypes
internal val ClassDescriptor.isInterface: Boolean
get() = (this.kind == ClassKind.INTERFACE)
private val konanInternalPackageName = FqName.fromSegments(listOf("konan", "internal"))
/**
* @return `konan.internal` member scope
*/
internal val KonanBuiltIns.konanInternal: MemberScope
get() = this.builtInsModule.getPackage(konanInternalPackageName).memberScope
internal val KotlinType.isKFunctionType: Boolean
get() {
val kind = constructor.declarationDescriptor?.getFunctionalClassKind()
return kind == FunctionClassDescriptor.Kind.KFunction
}
internal val FunctionDescriptor.isFunctionInvoke: Boolean
get() {
val dispatchReceiver = dispatchReceiverParameter ?: return false
assert(!dispatchReceiver.type.isKFunctionType)
return dispatchReceiver.type.isFunctionType &&
this.isOperator && this.name == OperatorNameConventions.INVOKE
}
internal fun ClassDescriptor.isUnit() = this.defaultType.isUnit()
internal val <T : CallableMemberDescriptor> T.allOverriddenDescriptors: List<T>
get() {
val result = mutableListOf<T>()
fun traverse(descriptor: T) {
result.add(descriptor)
@Suppress("UNCHECKED_CAST")
descriptor.overriddenDescriptors.forEach { traverse(it as T) }
}
traverse(this)
return result
}
internal val ClassDescriptor.contributedMethods: List<FunctionDescriptor>
get () = unsubstitutedMemberScope.contributedMethods
internal val MemberScope.contributedMethods: List<FunctionDescriptor>
get () {
val contributedDescriptors = this.getContributedDescriptors()
val functions = contributedDescriptors.filterIsInstance<FunctionDescriptor>()
val properties = contributedDescriptors.filterIsInstance<PropertyDescriptor>()
val getters = properties.mapNotNull { it.getter }
val setters = properties.mapNotNull { it.setter }
return functions + getters + setters
}
fun ClassDescriptor.isAbstract() = this.modality == Modality.SEALED || this.modality == Modality.ABSTRACT
|| this.kind == ClassKind.ENUM_CLASS
internal val FunctionDescriptor.target: FunctionDescriptor
get() = (if (modality == Modality.ABSTRACT) this else resolveFakeOverride()).original
tailrec internal fun DeclarationDescriptor.findPackage(): PackageFragmentDescriptor {
return if (this is PackageFragmentDescriptor) this
else this.containingDeclaration!!.findPackage()
}
internal fun DeclarationDescriptor.allContainingDeclarations(): List<DeclarationDescriptor> {
var list = mutableListOf<DeclarationDescriptor>()
var current = this.containingDeclaration
while (current != null) {
list.add(current)
current = current.containingDeclaration
}
return list
}
// It is possible to declare "external inline fun",
// but it doesn't have much sense for native,
// since externals don't have IR bodies.
// Enforce inlining of constructors annotated with @InlineConstructor.
private val inlineConstructor = FqName("konan.internal.InlineConstructor")
internal val FunctionDescriptor.needsInlining: Boolean
get() {
val inlineConstructor = annotations.hasAnnotation(inlineConstructor)
if (inlineConstructor) return true
return (this.isInline && !this.isExternal)
}
internal val FunctionDescriptor.needsSerializedIr: Boolean
get() = (this.needsInlining && this.isExported())
fun AnnotationDescriptor.getStringValueOrNull(name: String): String? {
val constantValue = this.allValueArguments.entries.atMostOne {
it.key.asString() == name
}?.value
return constantValue?.value as String?
}
fun AnnotationDescriptor.getStringValue(name: String): String = this.getStringValueOrNull(name)!!
private fun getPackagesFqNames(module: ModuleDescriptor): Set<FqName> {
val result = mutableSetOf<FqName>()
fun getSubPackages(fqName: FqName) {
result.add(fqName)
module.getSubPackagesOf(fqName) { true }.forEach { getSubPackages(it) }
}
getSubPackages(FqName.ROOT)
return result
}
fun ModuleDescriptor.getPackageFragments(): List<PackageFragmentDescriptor> =
getPackagesFqNames(this).flatMap {
getPackage(it).fragments.filter { it.module == this }
}
val ClassDescriptor.enumEntries: List<ClassDescriptor>
get() {
assert(this.kind == ClassKind.ENUM_CLASS)
return this.unsubstitutedMemberScope.getContributedDescriptors()
.filterIsInstance<ClassDescriptor>()
.filter { it.kind == ClassKind.ENUM_ENTRY }
}
internal val DeclarationDescriptor.isExpectMember: Boolean
get() = this is MemberDescriptor && this.isExpect
@@ -20,23 +20,22 @@ import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.backend.common.ir.Ir import org.jetbrains.kotlin.backend.common.ir.Ir
import org.jetbrains.kotlin.backend.common.ir.Symbols import org.jetbrains.kotlin.backend.common.ir.Symbols
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.KONAN_FUNCTION_INTERFACES_MAX_PARAMETERS
import org.jetbrains.kotlin.backend.konan.ValueType import org.jetbrains.kotlin.backend.konan.ValueType
import org.jetbrains.kotlin.backend.konan.descriptors.getMemberScope import org.jetbrains.kotlin.backend.konan.llvm.findMainEntryPoint
import org.jetbrains.kotlin.backend.konan.lower.TestProcessor import org.jetbrains.kotlin.backend.konan.lower.TestProcessor
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import kotlin.properties.Delegates import kotlin.properties.Delegates
@@ -51,10 +50,56 @@ internal class KonanIr(context: Context, irModule: IrModuleFragment): Ir<Context
lateinit var moduleIndexForCodegen: ModuleIndex lateinit var moduleIndexForCodegen: ModuleIndex
override var symbols: KonanSymbols by Delegates.notNull() override var symbols: KonanSymbols by Delegates.notNull()
fun getClass(type: KotlinType): IrClass? =
(type.constructor.declarationDescriptor as? ClassDescriptor)?.let { get(it) }
fun get(descriptor: FunctionDescriptor): IrFunction {
return moduleIndexForCodegen.functions[descriptor]
?: symbols.symbolTable.referenceFunction(descriptor).owner as IrFunction
}
fun get(descriptor: ClassDescriptor): IrClass {
return moduleIndexForCodegen.classes[descriptor]
?: symbols.symbolTable.referenceClass(descriptor)
.also {
if (!it.isBound)
error(descriptor)
}
.owner
}
fun getFromCurrentModule(descriptor: ClassDescriptor): IrClass = moduleIndexForCodegen.classes[descriptor]!!
fun getFromCurrentModule(descriptor: FunctionDescriptor): IrFunction = moduleIndexForCodegen.functions[descriptor]!!
fun getEnumEntryFromCurrentModule(descriptor: ClassDescriptor): IrEnumEntry =
originalModuleIndex.enumEntries[descriptor] ?: error(descriptor)
fun getEnumEntry(descriptor: ClassDescriptor): IrEnumEntry {
assert(descriptor.kind == ClassKind.ENUM_ENTRY)
return originalModuleIndex.enumEntries[descriptor]
?: symbols.symbolTable.referenceEnumEntry(descriptor).owner
}
fun getEnum(descriptor: ClassDescriptor): IrClass {
assert(descriptor.kind == ClassKind.ENUM_CLASS)
return originalModuleIndex.classes[descriptor]
?: symbols.symbolTable.referenceClass(descriptor).owner
}
} }
internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Symbols<Context>(context, symbolTable) { internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Symbols<Context>(context, symbolTable) {
val entryPoint = findMainEntryPoint(context)?.let { symbolTable.referenceSimpleFunction(it) }
val nothing = symbolTable.referenceClass(builtIns.nothing)
val throwable = symbolTable.referenceClass(builtIns.throwable)
val string = symbolTable.referenceClass(builtIns.string)
val arrayList = symbolTable.referenceClass(getArrayListClassDescriptor(context))
val interopNativePointedGetRawPointer = val interopNativePointedGetRawPointer =
symbolTable.referenceSimpleFunction(context.interopBuiltIns.nativePointedGetRawPointer) symbolTable.referenceSimpleFunction(context.interopBuiltIns.nativePointedGetRawPointer)
@@ -83,6 +128,15 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
val interopInterpretObjCPointerOrNull = val interopInterpretObjCPointerOrNull =
symbolTable.referenceSimpleFunction(context.interopBuiltIns.interpretObjCPointerOrNull) symbolTable.referenceSimpleFunction(context.interopBuiltIns.interpretObjCPointerOrNull)
val interopCreateNSStringFromKString =
symbolTable.referenceSimpleFunction(context.interopBuiltIns.CreateNSStringFromKString)
val objCPointerHolder = symbolTable.referenceClass(context.interopBuiltIns.objCPointerHolder)
val objCPointerHolderValueGetter =
symbolTable.referenceSimpleFunction(context.interopBuiltIns.objCPointerHolderValue.getter!!)
val allocObjCObject = symbolTable.referenceSimpleFunction(context.interopBuiltIns.allocObjCObject)
val getNativeNullPtr = symbolTable.referenceSimpleFunction(context.builtIns.getNativeNullPtr) val getNativeNullPtr = symbolTable.referenceSimpleFunction(context.builtIns.getNativeNullPtr)
val boxFunctions = ValueType.values().associate { val boxFunctions = ValueType.values().associate {
@@ -97,7 +151,7 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
val valueClassToBox = ValueType.values().associate { val valueClassToBox = ValueType.values().associate {
val valueClassId = ClassId.topLevel(it.classFqName.toSafe()) val valueClassId = ClassId.topLevel(it.classFqName.toSafe())
val valueClassDescriptor = context.builtIns.builtInsModule.findClassAcrossModuleDependencies(valueClassId)!! val valueClassDescriptor = context.builtIns.builtInsModule.findClassAcrossModuleDependencies(valueClassId)!!
valueClassDescriptor to boxClasses[it]!! symbolTable.referenceClass(valueClassDescriptor) to boxClasses[it]!!
} }
val unboxFunctions = ValueType.values().mapNotNull { val unboxFunctions = ValueType.values().mapNotNull {
@@ -235,6 +289,15 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND).single(predicate) .getContributedFunctions(name, NoLookupLocation.FROM_BACKEND).single(predicate)
) )
val functions = (0 .. KONAN_FUNCTION_INTERFACES_MAX_PARAMETERS)
.map { symbolTable.referenceClass(builtIns.getFunction(it)) }
val kFunctions = (0 .. KONAN_FUNCTION_INTERFACES_MAX_PARAMETERS)
.map { symbolTable.referenceClass(context.reflectionTypes.getKFunction(it)) }
val suspendFunctions = (0 .. KONAN_FUNCTION_INTERFACES_MAX_PARAMETERS)
.map { symbolTable.referenceClass(builtIns.getSuspendFunction(it)) }
val baseClassSuite = getKonanTestClass("BaseClassSuite") val baseClassSuite = getKonanTestClass("BaseClassSuite")
val topLevelSuite = getKonanTestClass("TopLevelSuite") val topLevelSuite = getKonanTestClass("TopLevelSuite")
val testFunctionKind = getKonanTestClass("TestFunctionKind") val testFunctionKind = getKonanTestClass("TestFunctionKind")
@@ -267,8 +330,17 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
private val testFunctionKindCache = mutableMapOf<TestProcessor.FunctionKind, IrEnumEntrySymbol>() private val testFunctionKindCache = mutableMapOf<TestProcessor.FunctionKind, IrEnumEntrySymbol>()
fun getTestFunctionKind(kind: TestProcessor.FunctionKind): IrEnumEntrySymbol = testFunctionKindCache.getOrPut(kind) { fun getTestFunctionKind(kind: TestProcessor.FunctionKind): IrEnumEntrySymbol = testFunctionKindCache.getOrPut(kind) {
symbolTable.referenceEnumEntry(testFunctionKind.descriptor.getMemberScope().getContributedClassifier( symbolTable.referenceEnumEntry(testFunctionKind.descriptor.unsubstitutedMemberScope.getContributedClassifier(
kind.runtimeKindName, NoLookupLocation.FROM_BACKEND kind.runtimeKindName, NoLookupLocation.FROM_BACKEND
) as ClassDescriptor) ) as ClassDescriptor)
} }
} }
private fun getArrayListClassDescriptor(context: Context): ClassDescriptor {
val module = context.builtIns.builtInsModule
val pkg = module.getPackage(FqName.fromSegments(listOf("kotlin", "collections")))
val classifier = pkg.memberScope.getContributedClassifier(Name.identifier("ArrayList"),
NoLookupLocation.FROM_BACKEND)
return classifier as ClassDescriptor
}
@@ -33,6 +33,8 @@ class ModuleIndex(val module: IrModuleFragment) {
*/ */
val classes: Map<ClassDescriptor, IrClass> val classes: Map<ClassDescriptor, IrClass>
val enumEntries: Map<ClassDescriptor, IrEnumEntry>
/** /**
* Contains all functions declared in [module] * Contains all functions declared in [module]
*/ */
@@ -41,6 +43,7 @@ class ModuleIndex(val module: IrModuleFragment) {
init { init {
val map = mutableMapOf<ClassDescriptor, IrClass>() val map = mutableMapOf<ClassDescriptor, IrClass>()
enumEntries = mutableMapOf()
module.acceptVoid(object : IrElementVisitorVoid { module.acceptVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) { override fun visitElement(element: IrElement) {
@@ -58,6 +61,12 @@ class ModuleIndex(val module: IrModuleFragment) {
map[declaration.descriptor] = declaration map[declaration.descriptor] = declaration
} }
override fun visitEnumEntry(declaration: IrEnumEntry) {
super.visitEnumEntry(declaration)
enumEntries[declaration.descriptor] = declaration
}
override fun visitFunction(declaration: IrFunction) { override fun visitFunction(declaration: IrFunction) {
super.visitFunction(declaration) super.visitFunction(declaration)
functions[declaration.descriptor] = declaration functions[declaration.descriptor] = declaration
@@ -0,0 +1,60 @@
/*
* Copyright 2010-2018 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.backend.konan.irasdescriptors
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.llvm.llvmSymbolOrigin
import org.jetbrains.kotlin.idea.MainFunctionDetector
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrCatch
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.module
// This file contains some IR utilities which actually use descriptors.
// TODO: port this code to IR.
internal val IrDeclaration.annotations get() = this.descriptor.annotations
internal val IrDeclaration.isAnonymousObject get() = DescriptorUtils.isAnonymousObject(this.descriptor)
internal val IrFunction.isExternal get() = this.descriptor.isExternal
internal val IrDeclaration.isLocal get() = DescriptorUtils.isLocal(this.descriptor)
internal val IrDeclaration.module get() = this.descriptor.module
@Deprecated("Do not call this method in the compiler front-end.")
internal val IrField.isDelegate get() = @Suppress("DEPRECATION") this.descriptor.isDelegated
internal fun IrFunction.getObjCMethodInfo() = this.descriptor.getObjCMethodInfo()
internal fun IrClass.isExternalObjCClass() = this.descriptor.isExternalObjCClass()
internal fun IrClass.isKotlinObjCClass() = this.descriptor.isKotlinObjCClass()
internal fun IrConstructor.getObjCInitMethod() = this.descriptor.getObjCInitMethod()
internal fun IrFunction.getExternalObjCMethodInfo() = this.descriptor.getExternalObjCMethodInfo()
internal fun IrFunction.isObjCClassMethod() = this.descriptor.isObjCClassMethod()
internal fun IrFunction.canObjCClassMethodBeCalledVirtually(overridden: IrFunction) =
this.descriptor.canObjCClassMethodBeCalledVirtually(overridden.descriptor)
internal fun IrClass.isObjCClass() = this.descriptor.isObjCClass()
internal fun IrFunction.isExternalObjCClassMethod() = this.descriptor.isExternalObjCClassMethod()
internal val IrDeclaration.llvmSymbolOrigin get() = this.descriptor.llvmSymbolOrigin
internal fun IrFunction.isMain() = MainFunctionDetector.isMain(this.descriptor)
internal fun IrTypeOperatorCall.getTypeOperandClass(context: Context): IrClass? =
context.ir.getClass(this.typeOperand)
internal fun IrCatch.getCatchParameterTypeClass(context: Context): IrClass? =
context.ir.getClass(this.catchParameter.type)
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2018 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.backend.konan.irasdescriptors
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
internal typealias DeclarationDescriptor = IrDeclaration
internal typealias FunctionDescriptor = IrFunction
internal typealias SimpleFunctionDescriptor = IrSimpleFunction
internal typealias ClassDescriptor = IrClass
internal typealias ConstructorDescriptor = IrConstructor
internal typealias ClassConstructorDescriptor = IrConstructor
internal typealias PackageFragmentDescriptor = IrPackageFragment
internal typealias VariableDescriptor = IrVariable
internal typealias ValueDescriptor = IrSymbolDeclaration<IrValueSymbol>
internal typealias ParameterDescriptor = IrValueParameter
@@ -0,0 +1,234 @@
/*
* Copyright 2010-2018 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.backend.konan.irasdescriptors
import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.backend.konan.descriptors.backingField
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.getTypeArgumentOrDefault
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
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)
else -> error(this)
}
val IrDeclaration.name: Name
get() = when (this) {
is IrSimpleFunction -> this.name
is IrClass -> this.name
is IrEnumEntry -> this.name
is IrProperty -> this.name
is IrLocalDelegatedProperty -> this.name
is IrField -> this.name
is IrVariable -> this.name
is IrConstructor -> SPECIAL_INIT_NAME
is IrValueParameter -> this.name
else -> error(this)
}
private val SPECIAL_INIT_NAME = Name.special("<init>")
val IrField.fqNameSafe: FqName get() = this.parent.fqNameSafe.child(this.name)
/**
* @return naturally-ordered list of all parameters available inside the function body.
*/
val IrFunction.allParameters: List<IrValueParameter>
get() = if (this is IrConstructor) {
listOf(this.constructedClass.thisReceiver
?: error(this.descriptor)
) + explicitParameters
} else {
explicitParameters
}
/**
* @return naturally-ordered list of the parameters that can have values specified at call site.
*/
val IrFunction.explicitParameters: List<IrValueParameter>
get() {
val result = ArrayList<IrValueParameter>(valueParameters.size + 2)
this.dispatchReceiverParameter?.let {
result.add(it)
}
this.extensionReceiverParameter?.let {
result.add(it)
}
result.addAll(valueParameters)
return result
}
val IrValueParameter.isVararg get() = this.varargElementType != null
val IrFunction.isSuspend get() = this is IrSimpleFunction && this.isSuspend
fun IrClass.isUnit() = this.fqNameSafe == KotlinBuiltIns.FQ_NAMES.unit.toSafe()
fun IrClass.getSuperClassNotAny() = this.superClasses.map { it.owner }.atMostOne { !it.isInterface && !it.isAny() }
fun IrClass.isAny() = this.fqNameSafe == KotlinBuiltIns.FQ_NAMES.any.toSafe()
fun IrClass.isNothing() = this.fqNameSafe == KotlinBuiltIns.FQ_NAMES.nothing.toSafe()
fun IrClass.getSuperInterfaces() = this.superClasses.map { it.owner }.filter { it.isInterface }
val IrProperty.konanBackingField: IrField?
get() {
this.backingField?.let { return it }
(this.descriptor as? DeserializedPropertyDescriptor)?.backingField?.let { backingFieldDescriptor ->
val result = IrFieldImpl(
this.startOffset,
this.endOffset,
IrDeclarationOrigin.PROPERTY_BACKING_FIELD,
backingFieldDescriptor
).also {
it.parent = this.parent
}
this.backingField = result
return result
}
return null
}
val IrClass.defaultType: KotlinType
get() = this.thisReceiver!!.type
val IrField.containingClass get() = this.parent as? IrClass
val IrFunction.isReal get() = this.origin != IrDeclarationOrigin.FAKE_OVERRIDE
val IrSimpleFunction.isOverridable: Boolean
get() = visibility != Visibilities.PRIVATE
&& modality != Modality.FINAL
&& (parent as? IrClass)?.isFinalClass != true
val IrFunction.isOverridable get() = this is IrSimpleFunction && this.isOverridable
val IrFunction.isOverridableOrOverrides
get() = this is IrSimpleFunction && (this.isOverridable || this.overriddenSymbols.isNotEmpty())
val IrClass.isFinalClass: Boolean
get() = modality == Modality.FINAL && kind != ClassKind.ENUM_CLASS
fun IrSimpleFunction.overrides(other: IrSimpleFunction): Boolean {
if (this == other) return true
this.overriddenSymbols.forEach {
if (it.owner.overrides(other)) {
return true
}
}
return false
}
fun IrClass.isSpecialClassWithNoSupertypes() = this.isAny() || this.isNothing()
val IrClass.constructors get() = this.declarations.filterIsInstance<IrConstructor>()
internal val IrValueParameter.isValueParameter get() = this.index >= 0
fun IrModuleFragment.referenceAllTypeExternalClassifiers(symbolTable: SymbolTable) {
val moduleDescriptor = this.descriptor
fun KotlinType.referenceAllClassifiers() {
TypeUtils.getClassDescriptor(this)?.let {
if (it.module != moduleDescriptor) {
if (it.kind == ClassKind.ENUM_ENTRY) {
symbolTable.referenceEnumEntry(it)
} else {
symbolTable.referenceClass(it)
}
}
}
this.constructor.supertypes.forEach {
it.referenceAllClassifiers()
}
}
val visitor = object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitValueParameter(declaration: IrValueParameter) {
super.visitValueParameter(declaration)
declaration.type.referenceAllClassifiers()
}
override fun visitVariable(declaration: IrVariable) {
super.visitVariable(declaration)
declaration.type.referenceAllClassifiers()
}
override fun visitExpression(expression: IrExpression) {
super.visitExpression(expression)
expression.type.referenceAllClassifiers()
}
override fun visitFunction(declaration: IrFunction) {
super.visitFunction(declaration)
declaration.returnType.referenceAllClassifiers()
}
override fun visitFunctionAccess(expression: IrFunctionAccessExpression) {
super.visitFunctionAccess(expression)
expression.descriptor.original.typeParameters.forEach {
expression.getTypeArgumentOrDefault(it).referenceAllClassifiers()
}
}
}
this.acceptVoid(visitor)
this.dependencyModules.forEach { module ->
module.externalPackageFragments.forEach {
it.acceptVoid(visitor)
}
}
}
@@ -17,26 +17,24 @@
package org.jetbrains.kotlin.backend.konan.llvm package org.jetbrains.kotlin.backend.konan.llvm
import llvm.LLVMTypeRef import llvm.LLVMTypeRef
import org.jetbrains.kotlin.backend.common.descriptors.allParameters
import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract
import org.jetbrains.kotlin.backend.konan.descriptors.isExpectMember import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.descriptors.isUnit
import org.jetbrains.kotlin.backend.konan.getObjCMethodInfo
import org.jetbrains.kotlin.backend.konan.isExternalObjCClass
import org.jetbrains.kotlin.backend.konan.isValueType import org.jetbrains.kotlin.backend.konan.isValueType
import org.jetbrains.kotlin.backend.konan.library.KonanLibraryReader import org.jetbrains.kotlin.backend.konan.library.KonanLibraryReader
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.components.isVararg
import org.jetbrains.kotlin.resolve.constants.StringValue import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
// This file describes the ABI for Kotlin descriptors of exported declarations. // This file describes the ABI for Kotlin descriptors of exported declarations.
// TODO: revise the naming scheme to ensure it produces unique names. // TODO: revise the naming scheme to ensure it produces unique names.
// TODO: do not serialize descriptors of non-exported declarations. // TODO: do not serialize descriptors of non-exported declarations.
@@ -49,7 +47,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
* and so should be computable from the descriptor itself without checking a backend state. * and so should be computable from the descriptor itself without checking a backend state.
*/ */
internal tailrec fun DeclarationDescriptor.isExported(): Boolean { internal tailrec fun DeclarationDescriptor.isExported(): Boolean {
assert(!this.isExpectMember) { this } // TODO: revise
if (this.annotations.findAnnotation(symbolNameAnnotation) != null) { if (this.annotations.findAnnotation(symbolNameAnnotation) != null) {
// Treat any `@SymbolName` declaration as exported. // Treat any `@SymbolName` declaration as exported.
@@ -73,7 +71,7 @@ internal tailrec fun DeclarationDescriptor.isExported(): Boolean {
return true return true
} }
if (DescriptorUtils.isAnonymousObject(this)) if (this.isAnonymousObject)
return false return false
if (this is ConstructorDescriptor && constructedClass.kind.isSingleton) { if (this is ConstructorDescriptor && constructedClass.kind.isSingleton) {
@@ -82,19 +80,33 @@ internal tailrec fun DeclarationDescriptor.isExported(): Boolean {
return constructedClass.isExported() return constructedClass.isExported()
} }
if (this is PropertyAccessorDescriptor) { if (this is IrFunction) {
return this.correspondingProperty.isExported() val descriptor = this.descriptor
// TODO: this code is required because accessor doesn't have a reference to property.
if (descriptor is PropertyAccessorDescriptor) {
val property = descriptor.correspondingProperty
if (property.annotations.hasAnnotation(inlineExposedAnnotation) ||
property.annotations.hasAnnotation(publishedApiAnnotation)) return true
}
} }
if (this is DeclarationDescriptorWithVisibility && !this.visibility.isPublicAPI) { val visibility = when (this) {
is IrClass -> this.visibility
is IrFunction -> this.visibility
is IrProperty -> this.visibility
is IrField -> this.visibility
else -> null
}
if (visibility != null && !visibility.isPublicAPI) {
// If the declaration is explicitly marked as non-public, // If the declaration is explicitly marked as non-public,
// then it must not be accessible from other modules. // then it must not be accessible from other modules.
return false return false
} }
if (this is DeclarationDescriptorNonRoot) { val parent = this.parent
// If the declaration is not root, then check its container too. if (parent is IrDeclaration) {
return containingDeclaration.isExported() return parent.isExported()
} }
return true return true
@@ -158,8 +170,8 @@ private val FunctionDescriptor.signature: String
val signatureSuffix = val signatureSuffix =
when { when {
this.typeParameters.isNotEmpty() -> "Generic" this.typeParameters.isNotEmpty() -> "Generic"
returnType.let { it != null && it.isValueType() } -> "ValueType" returnType.isValueType() -> "ValueType"
returnType.let { it != null && !KotlinBuiltIns.isUnitOrNullableUnit(it) } -> typeToHashString(returnType!!) !KotlinBuiltIns.isUnitOrNullableUnit(returnType) -> typeToHashString(returnType)
else -> "" else -> ""
} }
return "$extensionReceiverPart($argsPart)$signatureSuffix" return "$extensionReceiverPart($argsPart)$signatureSuffix"
@@ -188,7 +200,7 @@ internal val FunctionDescriptor.functionName: String
internal val FunctionDescriptor.symbolName: String internal val FunctionDescriptor.symbolName: String
get() { get() {
if (!this.isExported()) { if (!this.isExported()) {
throw AssertionError(this.toString()) throw AssertionError(this.descriptor.toString())
} }
this.annotations.findAnnotation(symbolNameAnnotation)?.let { this.annotations.findAnnotation(symbolNameAnnotation)?.let {
@@ -204,19 +216,20 @@ internal val FunctionDescriptor.symbolName: String
return name // no wrapping currently required return name // no wrapping currently required
} }
val containingDeclarationPart = containingDeclaration.fqNameSafe.let { val parent = this.parent
val containingDeclarationPart = parent.fqNameSafe.let {
if (it.isRoot) "" else "$it." if (it.isRoot) "" else "$it."
} }
return "kfun:$containingDeclarationPart$functionName" return "kfun:$containingDeclarationPart$functionName"
} }
internal val PropertyDescriptor.symbolName: String internal val IrField.symbolName: String
get() { get() {
val containingDeclarationPart = containingDeclaration.fqNameSafe.let { val containingDeclarationPart = parent.fqNameSafe.let {
if (it.isRoot) "" else "$it." if (it.isRoot) "" else "$it."
} }
val extensionReceiverPart = this.extensionReceiverParameter?.let { "${it.type}." } ?: "" return "kprop:$containingDeclarationPart$name"
return "kprop:$containingDeclarationPart$extensionReceiverPart$name"
} }
@@ -235,7 +248,7 @@ internal fun RuntimeAware.getLlvmFunctionType(function: FunctionDescriptor): LLV
val returnType = when { val returnType = when {
original is ConstructorDescriptor -> voidType original is ConstructorDescriptor -> voidType
original.isSuspend -> kObjHeaderPtr // Suspend functions return Any?. original.isSuspend -> kObjHeaderPtr // Suspend functions return Any?.
else -> getLLVMReturnType(original.returnType!!) else -> getLLVMReturnType(original.returnType)
} }
val paramTypes = ArrayList(original.allParameters.map { getLLVMType(it.type) }) val paramTypes = ArrayList(original.allParameters.map { getLLVMType(it.type) })
if (original.isSuspend) if (original.isSuspend)
@@ -21,14 +21,9 @@ import kotlinx.cinterop.*
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.backend.konan.descriptors.isUnit
import org.jetbrains.kotlin.backend.konan.descriptors.stdlibModule import org.jetbrains.kotlin.backend.konan.descriptors.stdlibModule
import org.jetbrains.kotlin.backend.konan.isObjCClass import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
internal class CodeGenerator(override val context: Context) : ContextUtils { internal class CodeGenerator(override val context: Context) : ContextUtils {
@@ -70,7 +65,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
fun typeInfoForAllocation(constructedClass: ClassDescriptor): LLVMValueRef { fun typeInfoForAllocation(constructedClass: ClassDescriptor): LLVMValueRef {
val descriptorForTypeInfo = if (constructedClass.isObjCClass()) { val descriptorForTypeInfo = if (constructedClass.isObjCClass()) {
context.interopBuiltIns.objCPointerHolder context.ir.symbols.objCPointerHolder.owner
} else { } else {
constructedClass constructedClass
} }
@@ -549,7 +544,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
assert (typeInfoPtr.type == codegen.kTypeInfoPtr) { LLVMPrintTypeToString(typeInfoPtr.type)!!.toKString() } assert (typeInfoPtr.type == codegen.kTypeInfoPtr) { LLVMPrintTypeToString(typeInfoPtr.type)!!.toKString() }
val llvmMethod = if (!owner.isInterface) { val llvmMethod = if (!owner.isInterface) {
// If this is a virtual method of the class - we can call via vtable. // If this is a virtual method of the class - we can call via vtable.
val index = context.getVtableBuilder(owner).vtableIndex(descriptor) val index = context.getVtableBuilder(owner).vtableIndex(descriptor as SimpleFunctionDescriptor)
val vtablePlace = gep(typeInfoPtr, Int32(1).llvm) // typeInfoPtr + 1 val vtablePlace = gep(typeInfoPtr, Int32(1).llvm) // typeInfoPtr + 1
val vtable = bitcast(kInt8PtrPtr, vtablePlace) val vtable = bitcast(kInt8PtrPtr, vtablePlace)
@@ -606,22 +601,20 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
/** /**
* Note: the same code is generated as IR in [org.jetbrains.kotlin.backend.konan.lower.EnumUsageLowering]. * Note: the same code is generated as IR in [org.jetbrains.kotlin.backend.konan.lower.EnumUsageLowering].
*/ */
fun getEnumEntry(descriptor: ClassDescriptor, exceptionHandler: ExceptionHandler): LLVMValueRef { fun getEnumEntry(descriptor: IrEnumEntry, exceptionHandler: ExceptionHandler): LLVMValueRef {
assert(descriptor.kind == ClassKind.ENUM_ENTRY)
val enumClassDescriptor = descriptor.containingDeclaration as ClassDescriptor val enumClassDescriptor = descriptor.containingDeclaration as ClassDescriptor
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClassDescriptor) val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClassDescriptor.descriptor)
val ordinal = loweredEnum.entriesMap[descriptor.name]!! val ordinal = loweredEnum.entriesMap[descriptor.name]!!
val values = call( val values = call(
loweredEnum.valuesGetter.descriptor.original.llvmFunction, loweredEnum.valuesGetter.llvmFunction,
emptyList(), emptyList(),
Lifetime.ARGUMENT, Lifetime.ARGUMENT,
exceptionHandler exceptionHandler
) )
return call( return call(
loweredEnum.itemGetterDescriptor.original.llvmFunction, loweredEnum.itemGetterSymbol.owner.llvmFunction,
listOf(values, Int32(ordinal).llvm), listOf(values, Int32(ordinal).llvm),
Lifetime.GLOBAL, Lifetime.GLOBAL,
exceptionHandler exceptionHandler
@@ -22,22 +22,19 @@ import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.CurrentKonanModule import org.jetbrains.kotlin.backend.konan.descriptors.CurrentKonanModule
import org.jetbrains.kotlin.backend.konan.descriptors.DeserializedKonanModule import org.jetbrains.kotlin.backend.konan.descriptors.DeserializedKonanModule
import org.jetbrains.kotlin.backend.konan.descriptors.LlvmSymbolOrigin import org.jetbrains.kotlin.backend.konan.descriptors.LlvmSymbolOrigin
import org.jetbrains.kotlin.backend.konan.descriptors.findPackage
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.backend.konan.hash.GlobalHash import org.jetbrains.kotlin.backend.konan.hash.GlobalHash
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.isNativeBinary import org.jetbrains.kotlin.backend.konan.isNativeBinary
import org.jetbrains.kotlin.backend.konan.library.KonanLibraryReader import org.jetbrains.kotlin.backend.konan.library.KonanLibraryReader
import org.jetbrains.kotlin.backend.konan.library.impl.LibraryReaderImpl import org.jetbrains.kotlin.backend.konan.library.impl.LibraryReaderImpl
import org.jetbrains.kotlin.backend.konan.library.withResolvedDependencies import org.jetbrains.kotlin.backend.konan.library.withResolvedDependencies
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
import org.jetbrains.kotlin.ir.declarations.IrField import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
@@ -162,7 +159,14 @@ internal interface ContextUtils : RuntimeAware {
val staticData: StaticData val staticData: StaticData
get() = context.llvm.staticData get() = context.llvm.staticData
fun isExternal(descriptor: DeclarationDescriptor) = descriptor.module != context.ir.irModule.descriptor fun isExternal(descriptor: DeclarationDescriptor): Boolean {
val pkg = descriptor.findPackage()
return when (pkg) {
is IrFile -> false
is IrExternalPackageFragment -> true
else -> error(pkg)
}
}
/** /**
* LLVM function generated from the Kotlin function. * LLVM function generated from the Kotlin function.
@@ -170,10 +174,7 @@ internal interface ContextUtils : RuntimeAware {
*/ */
val FunctionDescriptor.llvmFunction: LLVMValueRef val FunctionDescriptor.llvmFunction: LLVMValueRef
get() { get() {
assert (this.kind.isReal) assert (this.isReal)
if (this is TypeAliasConstructorDescriptor) {
return this.underlyingConstructorDescriptor.llvmFunction
}
return if (isExternal(this)) { return if (isExternal(this)) {
context.llvm.externalFunction(this.symbolName, getLlvmFunctionType(this), context.llvm.externalFunction(this.symbolName, getLlvmFunctionType(this),
@@ -209,12 +210,6 @@ internal interface ContextUtils : RuntimeAware {
val ClassDescriptor.llvmTypeInfoPtr: LLVMValueRef val ClassDescriptor.llvmTypeInfoPtr: LLVMValueRef
get() = typeInfoPtr.llvm get() = typeInfoPtr.llvm
/**
* Pointer to type info for this type, or `null` if the type doesn't have corresponding type info.
*/
val KotlinType.typeInfoPtr: ConstPointer?
get() = TypeUtils.getClassDescriptor(this)?.typeInfoPtr
/** /**
* Returns contents of this [GlobalHash]. * Returns contents of this [GlobalHash].
* *
@@ -21,8 +21,8 @@ import kotlinx.cinterop.memScoped
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.KonanVersion import org.jetbrains.kotlin.backend.konan.KonanVersion
import org.jetbrains.kotlin.backend.konan.irasdescriptors.FunctionDescriptor
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.SourceManager.FileEntry import org.jetbrains.kotlin.ir.SourceManager.FileEntry
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
@@ -185,7 +185,7 @@ private fun debugInfoBaseType(context:Context, targetData:LLVMTargetDataRef, typ
internal val FunctionDescriptor.types:List<KotlinType> internal val FunctionDescriptor.types:List<KotlinType>
get() { get() {
val parameters = valueParameters.map{it.type} val parameters = valueParameters.map{it.type}
return if (returnType != null) listOf(returnType!!, *parameters.toTypedArray()) else parameters return listOf(returnType, *parameters.toTypedArray())
} }
internal fun KotlinType.size(context:Context) = context.debugInfo.llvmTypeSizes.getOrDefault(this, context.debugInfo.otherTypeSize) internal fun KotlinType.size(context:Context) = context.debugInfo.llvmTypeSizes.getOrDefault(this, context.debugInfo.otherTypeSize)
@@ -52,7 +52,7 @@ internal fun findMainEntryPoint(context: Context): FunctionDescriptor? {
it.returnType?.isUnit() == true && it.returnType?.isUnit() == true &&
it.hasSingleArrayOfStringParameter && it.hasSingleArrayOfStringParameter &&
it.typeParameters.isEmpty() && it.typeParameters.isEmpty() &&
it.isExported() it.visibility.isPublicAPI
} }
if (main == null) { if (main == null) {
context.reportCompilationError("Could not find '$entryName' in '$packageName' package.") context.reportCompilationError("Could not find '$entryName' in '$packageName' package.")
@@ -19,39 +19,37 @@ package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.* import kotlinx.cinterop.*
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.common.descriptors.allParameters import org.jetbrains.kotlin.backend.common.descriptors.allParameters
import org.jetbrains.kotlin.backend.common.descriptors.isSuspend
import org.jetbrains.kotlin.backend.common.ir.ir2string import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.ir.* import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
import org.jetbrains.kotlin.backend.konan.optimizations.* import org.jetbrains.kotlin.backend.konan.optimizations.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.SourceManager import org.jetbrains.kotlin.ir.SourceManager
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptorBase
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
import org.jetbrains.kotlin.ir.util.getArguments import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isNothing import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.typeUtil.isUnit
internal fun emitLLVM(context: Context) { internal fun emitLLVM(context: Context) {
@@ -153,7 +151,7 @@ internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid {
override fun visitClass(declaration: IrClass) { override fun visitClass(declaration: IrClass) {
super.visitClass(declaration) super.visitClass(declaration)
val descriptor = declaration.descriptor val descriptor = declaration
if (descriptor.isIntrinsic) { if (descriptor.isIntrinsic) {
// do not generate any code for intrinsic classes as they require special handling // do not generate any code for intrinsic classes as they require special handling
return return
@@ -181,7 +179,7 @@ internal interface CodeContext {
* *
* @param value may be null iff target type is `Unit`. * @param value may be null iff target type is `Unit`.
*/ */
fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) fun genReturn(target: IrSymbolOwner, value: LLVMValueRef?)
fun genBreak(destination: IrBreak) fun genBreak(destination: IrBreak)
@@ -270,7 +268,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private object TopLevelCodeContext : CodeContext { private object TopLevelCodeContext : CodeContext {
private fun unsupported(any: Any? = null): Nothing = throw UnsupportedOperationException(any?.toString() ?: "") private fun unsupported(any: Any? = null): Nothing = throw UnsupportedOperationException(any?.toString() ?: "")
override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) = unsupported(target) override fun genReturn(target: IrSymbolOwner, value: LLVMValueRef?) = unsupported(target)
override fun genBreak(destination: IrBreak) = unsupported() override fun genBreak(destination: IrBreak) = unsupported()
@@ -347,7 +345,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
appendLlvmUsed("llvm.used", context.llvm.usedFunctions + context.llvm.usedGlobals) appendLlvmUsed("llvm.used", context.llvm.usedFunctions + context.llvm.usedGlobals)
appendLlvmUsed("llvm.compiler.used", context.llvm.compilerUsedGlobals) appendLlvmUsed("llvm.compiler.used", context.llvm.compilerUsedGlobals)
appendStaticInitializers() appendStaticInitializers()
appendEntryPointSelector(findMainEntryPoint(context)) appendEntryPointSelector(context.ir.symbols.entryPoint?.owner)
if (context.isDynamicLibrary) { if (context.isDynamicLibrary) {
appendCAdapters() appendCAdapters()
} }
@@ -371,7 +369,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
appendingTo(bbDeinit) { appendingTo(bbDeinit) {
context.llvm.fileInitializers.forEach { context.llvm.fileInitializers.forEach {
val descriptor = it.descriptor val descriptor = it
if (descriptor.type.isValueType()) if (descriptor.type.isValueType())
return@forEach // Is not a subject for memory management. return@forEach // Is not a subject for memory management.
val address = context.llvmDeclarations.forStaticField(descriptor).storage val address = context.llvmDeclarations.forStaticField(descriptor).storage
@@ -386,7 +384,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
.forEach { .forEach {
if (it.initializer?.expression !is IrConst<*>?) { if (it.initializer?.expression !is IrConst<*>?) {
val initialization = evaluateExpression(it.initializer!!.expression) val initialization = evaluateExpression(it.initializer!!.expression)
val address = context.llvmDeclarations.forStaticField(it.descriptor).storage val address = context.llvmDeclarations.forStaticField(it).storage
storeAny(initialization, address) storeAny(initialization, address)
} }
} }
@@ -479,7 +477,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
override fun visitConstructor(declaration: IrConstructor) { override fun visitConstructor(declaration: IrConstructor) {
context.log{"visitConstructor : ${ir2string(declaration)}"} context.log{"visitConstructor : ${ir2string(declaration)}"}
if (declaration.descriptor.containingDeclaration.isIntrinsic) { if (declaration.constructedClass.isIntrinsic) {
// Do not generate any ctors for intrinsic classes. // Do not generate any ctors for intrinsic classes.
return return
} }
@@ -489,18 +487,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
return return
} }
val constructorDescriptor = declaration.descriptor
val classDescriptor = constructorDescriptor.constructedClass
if (constructorDescriptor.isPrimary) {
if (DescriptorUtils.isObject(classDescriptor)) {
if (!classDescriptor.isUnit()) {
val objectPtr = codegen.getObjectInstanceStorage(classDescriptor)
LLVMSetInitializer(objectPtr, codegen.kNullObjHeaderPtr)
}
}
}
visitFunction(declaration) visitFunction(declaration)
} }
@@ -543,19 +529,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
function: IrFunction?, function: IrFunction?,
private val functionGenerationContext: FunctionGenerationContext): InnerScopeImpl() { private val functionGenerationContext: FunctionGenerationContext): InnerScopeImpl() {
val parameters = bindParameters(function?.descriptor) val parameters = bindParameters(function)
init { init {
if (function != null) { if (function != null) {
parameters.forEach{ parameters.forEach{
val descriptor = it.key val descriptor = it.key
val ir = when { val ir = descriptor
descriptor is ValueParameterDescriptor -> function.getIrValueParameter(descriptor)
descriptor is ReceiverParameterDescriptor && function.extensionReceiverParameter?.descriptor == descriptor -> function.extensionReceiverParameter!!
descriptor is ReceiverParameterDescriptor && function.dispatchReceiverParameter?.descriptor == descriptor-> function.dispatchReceiverParameter!!
function.descriptor is ClassConstructorDescriptor && (function.descriptor as ClassConstructorDescriptor).constructedClass.thisAsReceiverParameter == descriptor-> IrValueParameterImpl(function.startOffset, function.startOffset, object: IrDeclarationOriginImpl("THIS"){}, descriptor)
else -> TODO()
}
val local = functionGenerationContext.vars.createParameter(descriptor, val local = functionGenerationContext.vars.createParameter(descriptor,
debugInfoIfNeeded(function, ir)) debugInfoIfNeeded(function, ir))
@@ -587,15 +567,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
} }
var llvmFunction:LLVMValueRef? = declaration?.let{ var llvmFunction:LLVMValueRef? = declaration?.let{
codegen.llvmFunction(declaration.descriptor) codegen.llvmFunction(it)
} }
private var name:String? = declaration?.descriptor?.name?.asString() private var name:String? = declaration?.descriptor?.name?.asString()
override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) { override fun genReturn(target: IrSymbolOwner, value: LLVMValueRef?) {
if (declaration == null || target == declaration.descriptor) { if (declaration == null || target == declaration) {
if (target.returnsUnit()) { if ((target as IrFunction).returnsUnit()) {
assert (value == null)
functionGenerationContext.ret(null) functionGenerationContext.ret(null)
} else { } else {
functionGenerationContext.ret(value!!) functionGenerationContext.ret(value!!)
@@ -654,7 +633,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (declaration.descriptor.isExternal) return if (declaration.descriptor.isExternal) return
if (body == null) return if (body == null) return
generateFunction(codegen, declaration.descriptor, generateFunction(codegen, declaration,
declaration.location(declaration.startLine(), declaration.startColumn()), declaration.location(declaration.startLine(), declaration.startColumn()),
declaration.location(declaration.endLine(), declaration.endColumn())) { declaration.location(declaration.endLine(), declaration.endColumn())) {
using(FunctionScope(declaration, it)) { using(FunctionScope(declaration, it)) {
@@ -674,7 +653,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (declaration.descriptor.usedAnnotation) { if (declaration.descriptor.usedAnnotation) {
context.llvm.usedFunctions.add(codegen.llvmFunction(declaration.descriptor)) context.llvm.usedFunctions.add(codegen.llvmFunction(declaration))
} }
if (context.shouldVerifyBitCode()) if (context.shouldVerifyBitCode())
@@ -713,7 +692,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
override fun visitProperty(declaration: IrProperty) { override fun visitProperty(declaration: IrProperty) {
declaration.acceptChildrenVoid(this) declaration.getter?.acceptVoid(this)
declaration.setter?.acceptVoid(this)
declaration.backingField?.acceptVoid(this)
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
@@ -721,7 +702,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
override fun visitField(declaration: IrField) { override fun visitField(declaration: IrField) {
context.log{"visitField : ${ir2string(declaration)}"} context.log{"visitField : ${ir2string(declaration)}"}
debugFieldDeclaration(declaration) debugFieldDeclaration(declaration)
val descriptor = declaration.descriptor val descriptor = declaration
if (context.needGlobalInit(declaration)) { if (context.needGlobalInit(declaration)) {
val type = codegen.getLLVMType(descriptor.type) val type = codegen.getLLVMType(descriptor.type)
val globalProperty = context.llvmDeclarations.forStaticField(descriptor).storage val globalProperty = context.llvmDeclarations.forStaticField(descriptor).storage
@@ -791,7 +772,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateGetObjectValue(value: IrGetObjectValue): LLVMValueRef = private fun evaluateGetObjectValue(value: IrGetObjectValue): LLVMValueRef =
functionGenerationContext.getObjectValue( functionGenerationContext.getObjectValue(
value.descriptor, value.symbol.owner,
currentCodeContext.exceptionHandler, currentCodeContext.exceptionHandler,
value.startLocation value.startLocation
) )
@@ -872,10 +853,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
throw IllegalStateException("IrVararg neither was lowered nor can be statically evaluated") throw IllegalStateException("IrVararg neither was lowered nor can be statically evaluated")
} }
val arrayClass = context.ir.getClass(value.type)!!
// Note: even if all elements are const, they aren't guaranteed to be statically initialized. // Note: even if all elements are const, they aren't guaranteed to be statically initialized.
// E.g. an element may be a pointer to lazy-initialized object (aka singleton). // E.g. an element may be a pointer to lazy-initialized object (aka singleton).
// However it is guaranteed that all elements are already initialized at this point. // However it is guaranteed that all elements are already initialized at this point.
return codegen.staticData.createKotlinArray(value.type, elements) return codegen.staticData.createKotlinArray(arrayClass, elements)
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
@@ -999,7 +982,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
for (catch in catches) { for (catch in catches) {
fun genCatchBlock() { fun genCatchBlock() {
using(VariableScope()) { using(VariableScope()) {
currentCodeContext.genDeclareVariable(catch.parameter, exception, null) currentCodeContext.genDeclareVariable(catch.catchParameter, exception, null)
evaluateExpressionAndJump(catch.result, success) evaluateExpressionAndJump(catch.result, success)
} }
} }
@@ -1008,7 +991,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
genCatchBlock() genCatchBlock()
return // Remaining catch clauses are unreachable. return // Remaining catch clauses are unreachable.
} else { } else {
val isInstance = genInstanceOf(exception, catch.parameter.type) val isInstance = genInstanceOf(exception, catch.getCatchParameterTypeClass(context)!!)
val body = functionGenerationContext.basicBlock("catch", catch.startLocation) val body = functionGenerationContext.basicBlock("catch", catch.startLocation)
val nextCheck = functionGenerationContext.basicBlock("catchCheck", catch.endLocation) val nextCheck = functionGenerationContext.basicBlock("catchCheck", catch.endLocation)
functionGenerationContext.condBr(isInstance, body, nextCheck) functionGenerationContext.condBr(isInstance, body, nextCheck)
@@ -1143,7 +1126,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateGetValue(value: IrGetValue): LLVMValueRef { private fun evaluateGetValue(value: IrGetValue): LLVMValueRef {
context.log{"evaluateGetValue : ${ir2string(value)}"} context.log{"evaluateGetValue : ${ir2string(value)}"}
return currentCodeContext.genGetValue(value.descriptor) val symbol = value.symbol
val ir: IrSymbolDeclaration<IrValueSymbol> = when (symbol) {
is IrVariableSymbol -> symbol.owner
is IrValueParameterSymbol -> symbol.owner
else -> error(symbol)
}
return currentCodeContext.genGetValue(ir)
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
@@ -1151,7 +1141,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateSetVariable(value: IrSetVariable): LLVMValueRef { private fun evaluateSetVariable(value: IrSetVariable): LLVMValueRef {
context.log{"evaluateSetVariable : ${ir2string(value)}"} context.log{"evaluateSetVariable : ${ir2string(value)}"}
val result = evaluateExpression(value.value) val result = evaluateExpression(value.value)
val variable = currentCodeContext.getDeclaredVariable(value.descriptor) val variable = currentCodeContext.getDeclaredVariable(value.symbol.owner)
functionGenerationContext.vars.store(result, variable) functionGenerationContext.vars.store(result, variable)
assert(value.type.isUnit()) assert(value.type.isUnit())
return functionGenerationContext.theUnitInstanceRef.llvm return functionGenerationContext.theUnitInstanceRef.llvm
@@ -1177,7 +1167,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
functionScope = locationInfo.scope, functionScope = locationInfo.scope,
diType = element.descriptor.type.diType(context, codegen.llvmTargetData), diType = element.descriptor.type.diType(context, codegen.llvmTargetData),
name = element.descriptor.name, name = element.descriptor.name,
argNo = (element.descriptor as? ValueParameterDescriptor)?.index ?: 0, argNo = if (element.isValueParameter) element.index else 0,
file = file, file = file,
line = locationInfo.line, line = locationInfo.line,
location = location) location = location)
@@ -1189,7 +1179,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
context.log{"generateVariable : ${ir2string(variable)}"} context.log{"generateVariable : ${ir2string(variable)}"}
val value = variable.initializer?.let { evaluateExpression(it) } val value = variable.initializer?.let { evaluateExpression(it) }
currentCodeContext.genDeclareVariable( currentCodeContext.genDeclareVariable(
variable.descriptor, value, debugInfoIfNeeded( variable, value, debugInfoIfNeeded(
(currentCodeContext.functionScope() as FunctionScope).declaration, variable)) (currentCodeContext.functionScope() as FunctionScope).declaration, variable))
} }
@@ -1251,11 +1241,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateCast(value: IrTypeOperatorCall): LLVMValueRef { private fun evaluateCast(value: IrTypeOperatorCall): LLVMValueRef {
context.log{"evaluateCast : ${ir2string(value)}"} context.log{"evaluateCast : ${ir2string(value)}"}
val type = value.typeOperand val dstDescriptor = value.getTypeOperandClass(context)!!
assert(!KotlinBuiltIns.isPrimitiveType(type) && !KotlinBuiltIns.isPrimitiveType(value.argument.type))
assert(!type.isTypeParameter()) assert(!KotlinBuiltIns.isPrimitiveType(dstDescriptor.defaultType) &&
val dstDescriptor = TypeUtils.getClassDescriptor(type) // Get class descriptor for dst type. !KotlinBuiltIns.isPrimitiveType(value.argument.type))
val dstTypeInfo = codegen.typeInfoValue(dstDescriptor!!) // Get TypeInfo for dst type.
val dstTypeInfo = codegen.typeInfoValue(dstDescriptor) // Get TypeInfo for dst type.
val srcArg = evaluateExpression(value.argument) // Evaluate src expression. val srcArg = evaluateExpression(value.argument) // Evaluate src expression.
val srcObjInfoPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, srcArg) // Cast src to ObjInfoPtr. val srcObjInfoPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, srcArg) // Cast src to ObjInfoPtr.
val args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list. val args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list.
@@ -1283,7 +1274,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
functionGenerationContext.br(bbExit) functionGenerationContext.br(bbExit)
functionGenerationContext.positionAtEnd(bbInstanceOf) functionGenerationContext.positionAtEnd(bbInstanceOf)
val resultInstanceOf = genInstanceOf(srcArg, type) val typeOperandClass = value.getTypeOperandClass(context)
val resultInstanceOf = if (typeOperandClass != null) {
genInstanceOf(srcArg, typeOperandClass)
} else {
// E.g. when generating type operation with reified type parameter in the original body of inline function.
kTrue
// TODO: these code should be unreachable, however [BridgesBuilding] generates IR with such type checks.
}
functionGenerationContext.br(bbExit) functionGenerationContext.br(bbExit)
val bbInstanceOfResult = functionGenerationContext.currentBlock val bbInstanceOfResult = functionGenerationContext.currentBlock
@@ -1295,12 +1293,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun genInstanceOf(obj: LLVMValueRef, type: KotlinType): LLVMValueRef { private fun genInstanceOf(obj: LLVMValueRef, dstClass: IrClass): LLVMValueRef {
val dstDescriptor = TypeUtils.getClassDescriptor(type) ?: return kTrue // Get class descriptor for dst type. val dstTypeInfo = codegen.typeInfoValue(dstClass) // Get TypeInfo for dst type.
// Reified parameters are not yet supported.
// Workaround for reified parameters
val dstTypeInfo = codegen.typeInfoValue(dstDescriptor) // Get TypeInfo for dst type.
val srcObjInfoPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, obj) // Cast src to ObjInfoPtr. val srcObjInfoPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, obj) // Cast src to ObjInfoPtr.
val args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list. val args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list.
@@ -1322,11 +1316,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (value.descriptor.dispatchReceiverParameter != null) { if (value.descriptor.dispatchReceiverParameter != null) {
val thisPtr = evaluateExpression(value.receiver!!) val thisPtr = evaluateExpression(value.receiver!!)
return functionGenerationContext.loadSlot( return functionGenerationContext.loadSlot(
fieldPtrOfClass(thisPtr, value.descriptor), value.descriptor.isVar()) fieldPtrOfClass(thisPtr, value.symbol.owner), value.descriptor.isVar())
} }
else { else {
assert (value.receiver == null) assert (value.receiver == null)
val ptr = context.llvmDeclarations.forStaticField(value.descriptor).storage val ptr = context.llvmDeclarations.forStaticField(value.symbol.owner).storage
return functionGenerationContext.loadSlot(ptr, value.descriptor.isVar()) return functionGenerationContext.loadSlot(ptr, value.descriptor.isVar())
} }
} }
@@ -1339,11 +1333,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (value.descriptor.dispatchReceiverParameter != null) { if (value.descriptor.dispatchReceiverParameter != null) {
val thisPtr = evaluateExpression(value.receiver!!) val thisPtr = evaluateExpression(value.receiver!!)
functionGenerationContext.storeAny(valueToAssign, fieldPtrOfClass(thisPtr, value.descriptor)) functionGenerationContext.storeAny(valueToAssign, fieldPtrOfClass(thisPtr, value.symbol.owner))
} }
else { else {
assert (value.receiver == null) assert (value.receiver == null)
val globalValue = context.llvmDeclarations.forStaticField(value.descriptor).storage val globalValue = context.llvmDeclarations.forStaticField(value.symbol.owner).storage
functionGenerationContext.storeAny(valueToAssign, globalValue) functionGenerationContext.storeAny(valueToAssign, globalValue)
} }
@@ -1385,7 +1379,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
} }
*/ */
private fun fieldPtrOfClass(thisPtr: LLVMValueRef, value: PropertyDescriptor): LLVMValueRef { private fun fieldPtrOfClass(thisPtr: LLVMValueRef, value: IrField): LLVMValueRef {
val fieldInfo = context.llvmDeclarations.forField(value) val fieldInfo = context.llvmDeclarations.forField(value)
val classDescriptor = value.containingDeclaration as ClassDescriptor val classDescriptor = value.containingDeclaration as ClassDescriptor
@@ -1402,7 +1396,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
return if (classDescriptor.isObjCClass()) { return if (classDescriptor.isObjCClass()) {
assert(classDescriptor.isKotlinObjCClass()) assert(classDescriptor.isKotlinObjCClass())
val objCPtr = callDirect(context.interopBuiltIns.objCPointerHolderValue.getter!!, val objCPtr = callDirect(context.ir.symbols.objCPointerHolderValueGetter.owner,
listOf(objectPtr), Lifetime.IRRELEVANT) listOf(objectPtr), Lifetime.IRRELEVANT)
val objCDeclarations = context.llvmDeclarations.forClass(classDescriptor).objCDeclarations!! val objCDeclarations = context.llvmDeclarations.forClass(classDescriptor).objCDeclarations!!
@@ -1448,14 +1442,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val evaluated = evaluateExpression(value) val evaluated = evaluateExpression(value)
val target = expression.returnTarget val target = expression.returnTargetSymbol.owner
val ret = if (target.returnsUnit()) {
null
} else {
evaluated
}
currentCodeContext.genReturn(target, ret) currentCodeContext.genReturn(target, evaluated)
return codegen.kNothingFakeValue return codegen.kNothingFakeValue
} }
@@ -1487,15 +1476,15 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
return resultPhi!! return resultPhi!!
} }
override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) { override fun genReturn(target: IrSymbolOwner, value: LLVMValueRef?) {
if (target != returnableBlock.descriptor) { // It is not our "local return". if (target != returnableBlock) { // It is not our "local return".
super.genReturn(target, value) super.genReturn(target, value)
return return
} }
// It is local return from current function. // It is local return from current function.
functionGenerationContext.br(getExit()) // Generate branch on exit block. functionGenerationContext.br(getExit()) // Generate branch on exit block.
if (!target.returnsUnit()) { // If function returns more then "unit" if (!returnableBlock.type.isUnit()) { // If function returns more then "unit"
functionGenerationContext.assignPhis(getResult() to value!!) // Assign return value to result PHI node. functionGenerationContext.assignPhis(getResult() to value!!) // Assign return value to result PHI node.
} }
} }
@@ -1538,7 +1527,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private inner class ClassScope(val clazz:IrClass) : InnerScopeImpl() { private inner class ClassScope(val clazz:IrClass) : InnerScopeImpl() {
val isExported val isExported
get() = clazz.descriptor.isExported() get() = clazz.isExported()
var offsetInBits = 0L var offsetInBits = 0L
val members = mutableListOf<DIDerivedTypeRef>() val members = mutableListOf<DIDerivedTypeRef>()
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@@ -1547,7 +1536,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
tag = DwarfTag.DW_TAG_structure_type.value, tag = DwarfTag.DW_TAG_structure_type.value,
refBuilder = context.debugInfo.builder, refBuilder = context.debugInfo.builder,
refScope = (currentCodeContext.fileScope() as FileScope).file.file() as DIScopeOpaqueRef, refScope = (currentCodeContext.fileScope() as FileScope).file.file() as DIScopeOpaqueRef,
name = clazz.descriptor.typeInfoSymbolName, name = clazz.typeInfoSymbolName,
refFile = file().file(), refFile = file().file(),
line = clazz.startLine()) as DITypeOpaqueRef line = clazz.startLine()) as DITypeOpaqueRef
else null else null
@@ -1619,12 +1608,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun evaluateSpecialIntrinsicCall(expression: IrFunctionAccessExpression): LLVMValueRef? { private fun evaluateSpecialIntrinsicCall(expression: IrFunctionAccessExpression): LLVMValueRef? {
if (expression.descriptor.isIntrinsic) { val function = expression.symbol.owner as IrFunction
when (expression.descriptor.original) {
if (function.isIntrinsic) {
when (function.descriptor) {
context.interopBuiltIns.objCObjectInitBy -> { context.interopBuiltIns.objCObjectInitBy -> {
val receiver = evaluateExpression(expression.extensionReceiver!!) val receiver = evaluateExpression(expression.extensionReceiver!!)
val irConstructorCall = expression.getValueArgument(0) as IrCall val irConstructorCall = expression.getValueArgument(0) as IrCall
val constructorDescriptor = irConstructorCall.descriptor as ClassConstructorDescriptor val constructorDescriptor = irConstructorCall.symbol.owner as ClassConstructorDescriptor
val constructorArgs = evaluateExplicitArgs(irConstructorCall) val constructorArgs = evaluateExplicitArgs(irConstructorCall)
val args = listOf(receiver) + constructorArgs val args = listOf(receiver) + constructorArgs
callDirect(constructorDescriptor, args, Lifetime.IRRELEVANT) callDirect(constructorDescriptor, args, Lifetime.IRRELEVANT)
@@ -1641,7 +1632,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val callee = expression as IrCall val callee = expression as IrCall
val initializer = callee.getValueArgument(1) as IrCall val initializer = callee.getValueArgument(1) as IrCall
val thiz = evaluateExpression(callee.getValueArgument(0)!!) val thiz = evaluateExpression(callee.getValueArgument(0)!!)
evaluateSimpleFunctionCall(initializer.descriptor, listOf(thiz) + evaluateExplicitArgs(initializer), resultLifetime(initializer)) evaluateSimpleFunctionCall(
initializer.symbol.owner as IrFunction,
listOf(thiz) + evaluateExplicitArgs(initializer),
resultLifetime(initializer)
)
return codegen.theUnitInstanceRef.llvm return codegen.theUnitInstanceRef.llvm
} }
} }
@@ -1661,7 +1656,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
updateBuilderDebugLocation(value) updateBuilderDebugLocation(value)
when { when {
value is IrDelegatingConstructorCall -> value is IrDelegatingConstructorCall ->
return delegatingConstructorCall(value.descriptor, args) return delegatingConstructorCall(value.symbol.owner, args)
else -> else ->
return evaluateFunctionCall(value as IrCall, args, resultLifetime(value)) return evaluateFunctionCall(value as IrCall, args, resultLifetime(value))
@@ -1709,7 +1704,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
scope.members.add(DICreateMemberType( scope.members.add(DICreateMemberType(
refBuilder = context.debugInfo.builder, refBuilder = context.debugInfo.builder,
refScope = scope.scope as DIScopeOpaqueRef, refScope = scope.scope as DIScopeOpaqueRef,
name = expression.descriptor.symbolName, name = expression.symbolName,
file = irFile.file(), file = irFile.file(),
lineNum = expression.startLine(), lineNum = expression.startLine(),
sizeInBits = sizeInBits, sizeInBits = sizeInBits,
@@ -1740,7 +1735,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun IrFunction.scope():DIScopeOpaqueRef? = descriptor.scope(startLine()) private fun IrFunction.scope():DIScopeOpaqueRef? = this.scope(startLine())
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
private fun FunctionDescriptor.scope(startLine:Int): DIScopeOpaqueRef? { private fun FunctionDescriptor.scope(startLine:Int): DIScopeOpaqueRef? {
@@ -1781,9 +1776,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private val coroutineImplDescriptor = context.getInternalClass("CoroutineImpl") private val coroutineImplDescriptor = context.ir.symbols.coroutineImpl.owner
private val doResumeFunctionDescriptor = coroutineImplDescriptor.unsubstitutedMemberScope private val doResumeFunctionDescriptor = coroutineImplDescriptor.declarations
.getContributedFunctions(Name.identifier("doResume"), NoLookupLocation.FROM_BACKEND).single() .filterIsInstance<IrSimpleFunction>().single { it.name.asString() == "doResume" }
private fun getContinuation(): LLVMValueRef { private fun getContinuation(): LLVMValueRef {
val caller = functionGenerationContext.functionDescriptor!! val caller = functionGenerationContext.functionDescriptor!!
@@ -1791,13 +1786,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
codegen.param(caller, caller.allParameters.size) // The last argument. codegen.param(caller, caller.allParameters.size) // The last argument.
else { else {
// Suspend call from non-suspend function - must be [CoroutineImpl]. // Suspend call from non-suspend function - must be [CoroutineImpl].
assert (doResumeFunctionDescriptor in caller.overriddenDescriptors, assert (doResumeFunctionDescriptor.symbol in (caller as IrSimpleFunction).overriddenSymbols,
{ "Expected 'CoroutineImpl.doResume' but was '$caller'" }) { "Expected 'CoroutineImpl.doResume' but was '$caller'" })
currentCodeContext.genGetValue(caller.dispatchReceiverParameter!!) // Coroutine itself is a continuation. currentCodeContext.genGetValue(caller.dispatchReceiverParameter!!) // Coroutine itself is a continuation.
} }
} }
private fun CallableDescriptor.returnsUnit() = returnType == context.builtIns.unitType && !isSuspend private fun FunctionDescriptor.returnsUnit() = returnType == context.builtIns.unitType && !isSuspend
/** /**
* Evaluates all arguments of [expression] that are explicitly represented in the IR. * Evaluates all arguments of [expression] that are explicitly represented in the IR.
@@ -1824,7 +1819,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
assert (expression.getArguments().isEmpty()) assert (expression.getArguments().isEmpty())
val descriptor = expression.descriptor val descriptor = expression.symbol.owner as IrFunction
assert (descriptor.dispatchReceiverParameter == null) assert (descriptor.dispatchReceiverParameter == null)
val entry = codegen.functionEntryPointAddress(descriptor) val entry = codegen.functionEntryPointAddress(descriptor)
@@ -1887,7 +1882,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val bbResume = functionGenerationContext.basicBlock("resume", expression.resumeResult.startLocation) val bbResume = functionGenerationContext.basicBlock("resume", expression.resumeResult.startLocation)
val id = currentCodeContext.addResumePoint(bbResume) val id = currentCodeContext.addResumePoint(bbResume)
using (SuspensionPointScope(expression.suspensionPointIdParameter.descriptor, bbResume, id)) { using (SuspensionPointScope(expression.suspensionPointIdParameter, bbResume, id)) {
continuationBlock(expression.type, expression.result.startLocation).run { continuationBlock(expression.type, expression.result.startLocation).run {
val normalResult = evaluateExpression(expression.result) val normalResult = evaluateExpression(expression.result)
jump(this, normalResult) jump(this, normalResult)
@@ -1906,7 +1901,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateFunctionCall(callee: IrCall, args: List<LLVMValueRef>, private fun evaluateFunctionCall(callee: IrCall, args: List<LLVMValueRef>,
resultLifetime: Lifetime): LLVMValueRef { resultLifetime: Lifetime): LLVMValueRef {
val descriptor = callee.descriptor val descriptor = callee.symbol.owner as IrFunction
val argsWithContinuationIfNeeded = if (descriptor.isSuspend) val argsWithContinuationIfNeeded = if (descriptor.isSuspend)
args + getContinuation() args + getContinuation()
@@ -1918,11 +1913,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (callee is IrPrivateFunctionCall) if (callee is IrPrivateFunctionCall)
return evaluatePrivateFunctionCall(callee, argsWithContinuationIfNeeded, resultLifetime) return evaluatePrivateFunctionCall(callee, argsWithContinuationIfNeeded, resultLifetime)
when (descriptor) { when {
is IrBuiltinOperatorDescriptorBase -> return evaluateOperatorCall (callee, argsWithContinuationIfNeeded) descriptor.origin == IrDeclarationOrigin.IR_BUILTINS_STUB ->
is ConstructorDescriptor -> return evaluateConstructorCall (callee, argsWithContinuationIfNeeded) return evaluateOperatorCall(callee, argsWithContinuationIfNeeded)
else -> return evaluateSimpleFunctionCall(
descriptor, argsWithContinuationIfNeeded, resultLifetime, callee.superQualifier) descriptor is ConstructorDescriptor -> return evaluateConstructorCall(callee, argsWithContinuationIfNeeded)
else -> return evaluateSimpleFunctionCall(
descriptor, argsWithContinuationIfNeeded, resultLifetime, callee.superQualifierSymbol?.owner)
} }
} }
@@ -1940,9 +1938,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val functionPlacePtr = LLVMBuildGEP(functionGenerationContext.builder, functionsList, cValuesOf(kImmZero, functionIndex), 2, "")!! val functionPlacePtr = LLVMBuildGEP(functionGenerationContext.builder, functionsList, cValuesOf(kImmZero, functionIndex), 2, "")!!
val functionPtr = functionGenerationContext.load(functionPlacePtr) val functionPtr = functionGenerationContext.load(functionPlacePtr)
val functionPtrType = pointerType(codegen.getLlvmFunctionType(callee.descriptor)) val target = callee.symbol.owner as IrFunction
val functionPtrType = pointerType(codegen.getLlvmFunctionType(target))
val function = functionGenerationContext.bitcast(functionPtrType, functionPtr) val function = functionGenerationContext.bitcast(functionPtrType, functionPtr)
return call(callee.descriptor, function, args, resultLifetime) return call(target, function, args, resultLifetime)
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
@@ -1966,7 +1965,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
descriptor: FunctionDescriptor, args: List<LLVMValueRef>, descriptor: FunctionDescriptor, args: List<LLVMValueRef>,
resultLifetime: Lifetime, superClass: ClassDescriptor? = null): LLVMValueRef { resultLifetime: Lifetime, superClass: ClassDescriptor? = null): LLVMValueRef {
//context.log{"evaluateSimpleFunctionCall : $tmpVariableName = ${ir2string(value)}"} //context.log{"evaluateSimpleFunctionCall : $tmpVariableName = ${ir2string(value)}"}
if (descriptor.isOverridable && superClass == null) if (superClass == null && descriptor is SimpleFunctionDescriptor && descriptor.isOverridable)
return callVirtual(descriptor, args, resultLifetime) return callVirtual(descriptor, args, resultLifetime)
else else
return callDirect(descriptor, args, resultLifetime) return callDirect(descriptor, args, resultLifetime)
@@ -1980,7 +1979,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateConstructorCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef { private fun evaluateConstructorCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
context.log{"evaluateConstructorCall : ${ir2string(callee)}"} context.log{"evaluateConstructorCall : ${ir2string(callee)}"}
return memScoped { return memScoped {
val constructedClass = (callee.descriptor as ConstructorDescriptor).constructedClass val constructedClass = (callee.symbol as IrConstructorSymbol).owner.constructedClass
val thisValue = if (constructedClass.isArray) { val thisValue = if (constructedClass.isArray) {
assert(args.isNotEmpty() && args[0].type == int32Type) assert(args.isNotEmpty() && args[0].type == int32Type)
functionGenerationContext.allocArray(codegen.typeInfoValue(constructedClass), args[0], functionGenerationContext.allocArray(codegen.typeInfoValue(constructedClass), args[0],
@@ -1991,12 +1990,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
functionGenerationContext.allocArray(codegen.typeInfoValue(constructedClass), count = kImmZero, functionGenerationContext.allocArray(codegen.typeInfoValue(constructedClass), count = kImmZero,
lifetime = resultLifetime(callee)) lifetime = resultLifetime(callee))
} else if (constructedClass.isKotlinObjCClass()) { } else if (constructedClass.isKotlinObjCClass()) {
callDirect(context.interopBuiltIns.allocObjCObject, listOf(genGetObjCClass(constructedClass)), callDirect(context.ir.symbols.allocObjCObject.owner, listOf(genGetObjCClass(constructedClass)),
resultLifetime(callee)) resultLifetime(callee))
} else { } else {
functionGenerationContext.allocInstance(constructedClass, resultLifetime(callee)) functionGenerationContext.allocInstance(constructedClass, resultLifetime(callee))
} }
evaluateSimpleFunctionCall(callee.descriptor, evaluateSimpleFunctionCall(callee.symbol.owner as IrFunction,
listOf(thisValue) + args, Lifetime.IRRELEVANT /* constructor doesn't return anything */) listOf(thisValue) + args, Lifetime.IRRELEVANT /* constructor doesn't return anything */)
thisValue thisValue
} }
@@ -2074,8 +2073,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
interop.getObjCClass -> { interop.getObjCClass -> {
val typeArgument = callee.getTypeArgument(descriptor.typeParameters.single()) val typeArgument = callee.getTypeArgument(descriptor.typeParameters.single())
val classDescriptor = TypeUtils.getClassDescriptor(typeArgument!!)!! val irClass = context.ir.getClass(typeArgument!!)!!
genGetObjCClass(classDescriptor) genGetObjCClass(irClass)
} }
interop.getObjCMessenger -> { interop.getObjCMessenger -> {
@@ -2090,16 +2089,16 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
context.ir.symbols.getClassTypeInfo.descriptor -> { context.ir.symbols.getClassTypeInfo.descriptor -> {
val typeArgument = callee.getTypeArgumentOrDefault(descriptor.typeParameters.single()) val typeArgument = callee.getTypeArgumentOrDefault(descriptor.typeParameters.single())
val typeArgumentClass = TypeUtils.getClassDescriptor(typeArgument) val typeArgumentClass = context.ir.getClass(typeArgument)
if (typeArgumentClass == null) { if (typeArgumentClass == null) {
// E.g. for `T::class` in a body of an inline function itself. // E.g. for `T::class` in a body of an inline function itself.
functionGenerationContext.unreachable() functionGenerationContext.unreachable()
kNullInt8Ptr kNullInt8Ptr
} else { } else {
val classDescriptor = context.ir.symbols.valueClassToBox[typeArgumentClass]?.descriptor val irClass = context.ir.symbols.valueClassToBox[typeArgumentClass.symbol]?.owner
?: typeArgumentClass ?: typeArgumentClass
val typeInfo = codegen.typeInfoValue(classDescriptor) val typeInfo = codegen.typeInfoValue(irClass)
LLVMConstBitCast(typeInfo, kInt8Ptr)!! LLVMConstBitCast(typeInfo, kInt8Ptr)!!
} }
} }
@@ -2107,8 +2106,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
context.ir.symbols.createUninitializedInstance.descriptor -> { context.ir.symbols.createUninitializedInstance.descriptor -> {
val typeParameterT = context.ir.symbols.createUninitializedInstance.descriptor.typeParameters[0] val typeParameterT = context.ir.symbols.createUninitializedInstance.descriptor.typeParameters[0]
val enumClass = callee.getTypeArgument(typeParameterT)!! val enumClass = callee.getTypeArgument(typeParameterT)!!
val enumClassDescriptor = enumClass.constructor.declarationDescriptor as ClassDescriptor val enumIrClass = context.ir.getClass(enumClass)!!
functionGenerationContext.allocInstance(enumClassDescriptor, resultLifetime(callee)) functionGenerationContext.allocInstance(enumIrClass, resultLifetime(callee))
} }
context.ir.symbols.listOfInternal.descriptor -> { context.ir.symbols.listOfInternal.descriptor -> {
@@ -2301,7 +2300,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
} }
private fun genObjCObjectInitFromPtr(args: List<LLVMValueRef>): LLVMValueRef { private fun genObjCObjectInitFromPtr(args: List<LLVMValueRef>): LLVMValueRef {
return callDirect(context.interopBuiltIns.objCPointerHolder.unsubstitutedPrimaryConstructor!!, return callDirect(context.ir.symbols.objCPointerHolder.owner.constructors.single(),
args, Lifetime.IRRELEVANT) args, Lifetime.IRRELEVANT)
} }
@@ -2335,13 +2334,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateOperatorCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef { private fun evaluateOperatorCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
context.log{"evaluateOperatorCall : origin:${ir2string(callee)}"} context.log{"evaluateOperatorCall : origin:${ir2string(callee)}"}
val descriptor = callee.descriptor val descriptor = callee.symbol.owner as IrFunction
val ib = context.irModule!!.irBuiltins val ib = context.irModule!!.irBuiltins
with(functionGenerationContext) { with(functionGenerationContext) {
return when { return when {
descriptor == ib.eqeqeq -> icmpEq(args[0], args[1]) descriptor == ib.eqeqeqFun -> icmpEq(args[0], args[1])
descriptor == ib.booleanNot -> icmpNe(args[0], kTrue) descriptor == ib.booleanNotFun -> icmpNe(args[0], kTrue)
descriptor.isComparisonDescriptor(ib.greaterFunByOperandType) -> { descriptor.isComparisonDescriptor(ib.greaterFunByOperandType) -> {
if (args[0].type.isFloatingPoint()) fcmpGt(args[0], args[1]) if (args[0].type.isFloatingPoint()) fcmpGt(args[0], args[1])
@@ -2447,7 +2446,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
descriptor: ClassConstructorDescriptor, args: List<LLVMValueRef>): LLVMValueRef { descriptor: ClassConstructorDescriptor, args: List<LLVMValueRef>): LLVMValueRef {
val constructedClass = functionGenerationContext.constructedClass!! val constructedClass = functionGenerationContext.constructedClass!!
val thisPtr = currentCodeContext.genGetValue(constructedClass.thisAsReceiverParameter) val thisPtr = currentCodeContext.genGetValue(constructedClass.thisReceiver!!)
if (constructedClass.isObjCClass()) { if (constructedClass.isObjCClass()) {
return codegen.theUnitInstanceRef.llvm return codegen.theUnitInstanceRef.llvm
@@ -18,44 +18,40 @@ package org.jetbrains.kotlin.backend.konan.llvm
import llvm.LLVMStoreSizeOfType import llvm.LLVMStoreSizeOfType
import llvm.LLVMValueRef import llvm.LLVMValueRef
import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.contributedMethods
import org.jetbrains.kotlin.backend.konan.descriptors.getStringValue import org.jetbrains.kotlin.backend.konan.descriptors.getStringValue
import org.jetbrains.kotlin.backend.konan.descriptors.getStringValueOrNull import org.jetbrains.kotlin.backend.konan.descriptors.getStringValueOrNull
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.isFinalClass
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.simpleFunctions
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
internal class KotlinObjCClassInfoGenerator(override val context: Context) : ContextUtils { internal class KotlinObjCClassInfoGenerator(override val context: Context) : ContextUtils {
fun generate(irClass: IrClass) { fun generate(irClass: IrClass) {
val descriptor = irClass.descriptor assert(irClass.isFinalClass)
assert(descriptor.isFinalClass)
val objCLLvmDeclarations = context.llvmDeclarations.forClass(descriptor).objCDeclarations!! val objCLLvmDeclarations = context.llvmDeclarations.forClass(irClass).objCDeclarations!!
val instanceMethods = generateInstanceMethodDescs(irClass) val instanceMethods = generateInstanceMethodDescs(irClass)
val companionObjectDescriptor = descriptor.companionObjectDescriptor val companionObject = irClass.declarations.filterIsInstance<IrClass>().atMostOne { it.isCompanion }
val classMethods = companionObjectDescriptor?.generateOverridingMethodDescs() ?: emptyList() val classMethods = companionObject?.generateOverridingMethodDescs() ?: emptyList()
val superclassName = descriptor.getSuperClassNotAny()!!.let { val superclassName = irClass.getSuperClassNotAny()!!.let {
context.llvm.imports.add(it.llvmSymbolOrigin) context.llvm.imports.add(it.llvmSymbolOrigin)
it.name.asString() it.name.asString()
} }
val protocolNames = descriptor.getSuperInterfaces().map { val protocolNames = irClass.getSuperInterfaces().map {
context.llvm.imports.add(it.llvmSymbolOrigin) context.llvm.imports.add(it.llvmSymbolOrigin)
it.name.asString().removeSuffix("Protocol") it.name.asString().removeSuffix("Protocol")
} }
val bodySize = val bodySize =
LLVMStoreSizeOfType(llvmTargetData, context.llvmDeclarations.forClass(descriptor).bodyType).toInt() LLVMStoreSizeOfType(llvmTargetData, context.llvmDeclarations.forClass(irClass).bodyType).toInt()
val className = selectClassName(descriptor)?.let { staticData.cStringLiteral(it) } ?: NullPointer(int8Type) val className = selectClassName(irClass)?.let { staticData.cStringLiteral(it) } ?: NullPointer(int8Type)
val info = Struct(runtime.kotlinObjCClassInfo, val info = Struct(runtime.kotlinObjCClassInfo,
className, className,
@@ -73,8 +69,8 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
Int32(bodySize), Int32(bodySize),
objCLLvmDeclarations.bodyOffsetGlobal.pointer, objCLLvmDeclarations.bodyOffsetGlobal.pointer,
descriptor.typeInfoPtr, irClass.typeInfoPtr,
companionObjectDescriptor?.typeInfoPtr ?: NullPointer(runtime.typeInfoType), companionObject?.typeInfoPtr ?: NullPointer(runtime.typeInfoType),
objCLLvmDeclarations.classPointerGlobal.pointer objCLLvmDeclarations.classPointerGlobal.pointer
) )
@@ -88,13 +84,12 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
private fun generateInstanceMethodDescs( private fun generateInstanceMethodDescs(
irClass: IrClass irClass: IrClass
): List<ObjCMethodDesc> = mutableListOf<ObjCMethodDesc>().apply { ): List<ObjCMethodDesc> = mutableListOf<ObjCMethodDesc>().apply {
val descriptor = irClass.descriptor addAll(irClass.generateOverridingMethodDescs())
addAll(descriptor.generateOverridingMethodDescs())
addAll(irClass.generateImpMethodDescs()) addAll(irClass.generateImpMethodDescs())
val allImplementedSelectors = this.map { it.selector }.toSet() val allImplementedSelectors = this.map { it.selector }.toSet()
assert(descriptor.getSuperClassNotAny()!!.isExternalObjCClass()) assert(irClass.getSuperClassNotAny()!!.isExternalObjCClass())
val allInitMethodsInfo = descriptor.getSuperClassNotAny()!!.constructors val allInitMethodsInfo = irClass.getSuperClassNotAny()!!.constructors
.mapNotNull { it.getObjCInitMethod()?.getExternalObjCMethodInfo() } .mapNotNull { it.getObjCInitMethod()?.getExternalObjCMethodInfo() }
.filter { it.selector !in allImplementedSelectors } .filter { it.selector !in allImplementedSelectors }
.distinctBy { it.selector } .distinctBy { it.selector }
@@ -104,14 +99,14 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
} }
} }
private fun selectClassName(descriptor: ClassDescriptor): String? { private fun selectClassName(irClass: IrClass): String? {
val exportObjCClassAnnotation = val exportObjCClassAnnotation =
descriptor.annotations.findAnnotation(context.interopBuiltIns.exportObjCClass.fqNameSafe) irClass.annotations.findAnnotation(context.interopBuiltIns.exportObjCClass.fqNameSafe)
return if (exportObjCClassAnnotation != null) { return if (exportObjCClassAnnotation != null) {
exportObjCClassAnnotation.getStringValueOrNull("name") ?: descriptor.name.asString() exportObjCClassAnnotation.getStringValueOrNull("name") ?: irClass.name.asString()
} else if (descriptor.isExported()) { } else if (irClass.isExported()) {
descriptor.fqNameSafe.asString() irClass.fqNameSafe.asString()
} else { } else {
null // Generate as anonymous. null // Generate as anonymous.
} }
@@ -138,22 +133,21 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
) )
) )
private fun ClassDescriptor.generateOverridingMethodDescs(): List<ObjCMethodDesc> = private fun IrClass.generateOverridingMethodDescs(): List<ObjCMethodDesc> =
this.unsubstitutedMemberScope.contributedMethods.filter { this.simpleFunctions().filter { it.isReal }
it.kind.isReal && it !is ConstructorDescriptor .mapNotNull { it.getObjCMethodInfo() }.map { generateMethodDesc(it) }
}.mapNotNull { it.getObjCMethodInfo() }.map { generateMethodDesc(it) }
private fun IrClass.generateImpMethodDescs(): List<ObjCMethodDesc> = this.declarations private fun IrClass.generateImpMethodDescs(): List<ObjCMethodDesc> = this.declarations
.filterIsInstance<IrSimpleFunction>() .filterIsInstance<IrSimpleFunction>()
.mapNotNull { .mapNotNull {
val annotation = val annotation =
it.descriptor.annotations.findAnnotation(context.interopBuiltIns.objCMethodImp.fqNameSafe) ?: it.annotations.findAnnotation(context.interopBuiltIns.objCMethodImp.fqNameSafe) ?:
return@mapNotNull null return@mapNotNull null
ObjCMethodDesc( ObjCMethodDesc(
annotation.getStringValue("selector"), annotation.getStringValue("selector"),
annotation.getStringValue("encoding"), annotation.getStringValue("encoding"),
it.descriptor.llvmFunction it.llvmFunction
) )
} }
} }
@@ -20,18 +20,13 @@ import kotlinx.cinterop.*
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.idea.MainFunctionDetector
import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
internal fun createLlvmDeclarations(context: Context): LlvmDeclarations { internal fun createLlvmDeclarations(context: Context): LlvmDeclarations {
val generator = DeclarationsGeneratorVisitor(context) val generator = DeclarationsGeneratorVisitor(context)
@@ -47,8 +42,8 @@ internal fun createLlvmDeclarations(context: Context): LlvmDeclarations {
internal class LlvmDeclarations( internal class LlvmDeclarations(
private val functions: Map<FunctionDescriptor, FunctionLlvmDeclarations>, private val functions: Map<FunctionDescriptor, FunctionLlvmDeclarations>,
private val classes: Map<ClassDescriptor, ClassLlvmDeclarations>, private val classes: Map<ClassDescriptor, ClassLlvmDeclarations>,
private val fields: Map<PropertyDescriptor, FieldLlvmDeclarations>, private val fields: Map<IrField, FieldLlvmDeclarations>,
private val staticFields: Map<PropertyDescriptor, StaticFieldLlvmDeclarations>, private val staticFields: Map<IrField, StaticFieldLlvmDeclarations>,
private val theUnitInstanceRef: ConstPointer? private val theUnitInstanceRef: ConstPointer?
) { ) {
fun forFunction(descriptor: FunctionDescriptor) = functions[descriptor] ?: fun forFunction(descriptor: FunctionDescriptor) = functions[descriptor] ?:
@@ -57,10 +52,10 @@ internal class LlvmDeclarations(
fun forClass(descriptor: ClassDescriptor) = classes[descriptor] ?: fun forClass(descriptor: ClassDescriptor) = classes[descriptor] ?:
error(descriptor.toString()) error(descriptor.toString())
fun forField(descriptor: PropertyDescriptor) = fields[descriptor] ?: fun forField(descriptor: IrField) = fields[descriptor] ?:
error(descriptor.toString()) error(descriptor.toString())
fun forStaticField(descriptor: PropertyDescriptor) = staticFields[descriptor] ?: fun forStaticField(descriptor: IrField) = staticFields[descriptor] ?:
error(descriptor.toString()) error(descriptor.toString())
fun forSingleton(descriptor: ClassDescriptor) = forClass(descriptor).singletonDeclarations ?: fun forSingleton(descriptor: ClassDescriptor) = forClass(descriptor).singletonDeclarations ?:
@@ -72,7 +67,7 @@ internal class LlvmDeclarations(
internal class ClassLlvmDeclarations( internal class ClassLlvmDeclarations(
val bodyType: LLVMTypeRef, val bodyType: LLVMTypeRef,
val fields: List<PropertyDescriptor>, // TODO: it is not an LLVM declaration. val fields: List<IrField>, // TODO: it is not an LLVM declaration.
val typeInfoGlobal: StaticData.Global, val typeInfoGlobal: StaticData.Global,
val writableTypeInfoGlobal: StaticData.Global?, val writableTypeInfoGlobal: StaticData.Global?,
val typeInfo: ConstPointer, val typeInfo: ConstPointer,
@@ -101,7 +96,7 @@ internal class StaticFieldLlvmDeclarations(val storage: LLVMValueRef)
*/ */
internal fun ContextUtils.getFields(classDescriptor: ClassDescriptor) = context.getFields(classDescriptor) internal fun ContextUtils.getFields(classDescriptor: ClassDescriptor) = context.getFields(classDescriptor)
internal fun Context.getFields(classDescriptor: ClassDescriptor): List<PropertyDescriptor> { internal fun Context.getFields(classDescriptor: ClassDescriptor): List<IrField> {
val superClass = classDescriptor.getSuperClassNotAny() // TODO: what if Any has fields? val superClass = classDescriptor.getSuperClassNotAny() // TODO: what if Any has fields?
val superFields = if (superClass != null) getFields(superClass) else emptyList() val superFields = if (superClass != null) getFields(superClass) else emptyList()
@@ -111,7 +106,7 @@ internal fun Context.getFields(classDescriptor: ClassDescriptor): List<PropertyD
/** /**
* Fields declared in the class. * Fields declared in the class.
*/ */
private fun Context.getDeclaredFields(classDescriptor: ClassDescriptor): List<PropertyDescriptor> { private fun Context.getDeclaredFields(classDescriptor: ClassDescriptor): List<IrField> {
// TODO: Here's what is going on here: // TODO: Here's what is going on here:
// The existence of a backing field for a property is only described in the IR, // The existence of a backing field for a property is only described in the IR,
// but not in the PropertyDescriptor. // but not in the PropertyDescriptor.
@@ -122,33 +117,24 @@ private fun Context.getDeclaredFields(classDescriptor: ClassDescriptor): List<Pr
// In this function we check the presence of the backing field // In this function we check the presence of the backing field
// two ways: first we check IR, then we check the protobuf extension. // two ways: first we check IR, then we check the protobuf extension.
val irClass = ir.moduleIndexForCodegen.classes[classDescriptor] val irClass = classDescriptor
val fields = if (irClass != null) { val fields = irClass.declarations.mapNotNull {
val declarations = irClass.declarations when (it) {
is IrField -> it
declarations.mapNotNull { is IrProperty -> it.konanBackingField
when (it) { else -> null
is IrProperty -> it.backingField?.descriptor
is IrField -> it.descriptor
else -> null
}
} }
} else {
val properties = classDescriptor.unsubstitutedMemberScope.
getContributedDescriptors().
filterIsInstance<DeserializedPropertyDescriptor>()
properties.mapNotNull { it.backingField }
} }
return fields.sortedBy { return fields.sortedBy {
it.fqNameSafe.localHash.value it.fqNameSafe.localHash.value
} }
} }
private fun ContextUtils.createClassBodyType(name: String, fields: List<PropertyDescriptor>): LLVMTypeRef { private fun ContextUtils.createClassBodyType(name: String, fields: List<IrField>): LLVMTypeRef {
val fieldTypes = fields.map { val fieldTypes = fields.map {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
getLLVMType(if (it.isDelegated) context.builtIns.nullableAnyType else it.type) getLLVMType(if (it.isDelegate) context.builtIns.nullableAnyType else it.type)
} }
val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), name)!! val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), name)!!
@@ -163,8 +149,8 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
val functions = mutableMapOf<FunctionDescriptor, FunctionLlvmDeclarations>() val functions = mutableMapOf<FunctionDescriptor, FunctionLlvmDeclarations>()
val classes = mutableMapOf<ClassDescriptor, ClassLlvmDeclarations>() val classes = mutableMapOf<ClassDescriptor, ClassLlvmDeclarations>()
val fields = mutableMapOf<PropertyDescriptor, FieldLlvmDeclarations>() val fields = mutableMapOf<IrField, FieldLlvmDeclarations>()
val staticFields = mutableMapOf<PropertyDescriptor, StaticFieldLlvmDeclarations>() val staticFields = mutableMapOf<IrField, StaticFieldLlvmDeclarations>()
var theUnitInstanceRef: ConstPointer? = null var theUnitInstanceRef: ConstPointer? = null
private class Namer(val prefix: String) { private class Namer(val prefix: String) {
@@ -183,7 +169,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
val objectNamer = Namer("object-") val objectNamer = Namer("object-")
private fun getLocalName(parent: FqName, descriptor: DeclarationDescriptor): Name { private fun getLocalName(parent: FqName, descriptor: DeclarationDescriptor): Name {
if (DescriptorUtils.isAnonymousObject(descriptor)) { if (descriptor.isAnonymousObject) {
return objectNamer.getName(parent, descriptor) return objectNamer.getName(parent, descriptor)
} }
@@ -191,20 +177,15 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
} }
private fun getFqName(descriptor: DeclarationDescriptor): FqName { private fun getFqName(descriptor: DeclarationDescriptor): FqName {
if (descriptor is PackageFragmentDescriptor) { val parent = descriptor.parent
return descriptor.fqName val parentFqName = when (parent) {
is IrPackageFragment -> parent.fqName
is IrDeclaration -> getFqName(parent)
else -> error(parent)
} }
val localName = getLocalName(parentFqName, descriptor)
val containingDeclaration = descriptor.containingDeclaration return parentFqName.child(localName)
val parent = if (containingDeclaration != null) {
getFqName(containingDeclaration)
} else {
FqName.ROOT
}
val localName = getLocalName(parent, descriptor)
return parent.child(localName)
} }
/** /**
@@ -223,17 +204,17 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
override fun visitClass(declaration: IrClass) { override fun visitClass(declaration: IrClass) {
if (declaration.descriptor.isIntrinsic) { if (declaration.isIntrinsic) {
// do not generate any declarations for intrinsic classes as they require special handling // do not generate any declarations for intrinsic classes as they require special handling
} else { } else {
this.classes[declaration.descriptor] = createClassDeclarations(declaration) this.classes[declaration] = createClassDeclarations(declaration)
} }
super.visitClass(declaration) super.visitClass(declaration)
} }
private fun createClassDeclarations(declaration: IrClass): ClassLlvmDeclarations { private fun createClassDeclarations(declaration: IrClass): ClassLlvmDeclarations {
val descriptor = declaration.descriptor val descriptor = declaration
val internalName = qualifyInternalName(descriptor) val internalName = qualifyInternalName(descriptor)
@@ -317,7 +298,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
): SingletonLlvmDeclarations? { ): SingletonLlvmDeclarations? {
if (descriptor.isUnit()) { if (descriptor.isUnit()) {
this.theUnitInstanceRef = staticData.createUnitInstance(descriptor, bodyType, typeInfoPtr) this.theUnitInstanceRef = staticData.createUnitInstance(bodyType, typeInfoPtr)
return null return null
} }
@@ -330,6 +311,8 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
val instanceFieldRef = addGlobal( val instanceFieldRef = addGlobal(
symbolName, getLLVMType(descriptor.defaultType), isExported = isExported, threadLocal = true) symbolName, getLLVMType(descriptor.defaultType), isExported = isExported, threadLocal = true)
LLVMSetInitializer(instanceFieldRef, kNullObjHeaderPtr)
return SingletonLlvmDeclarations(instanceFieldRef) return SingletonLlvmDeclarations(instanceFieldRef)
} }
@@ -353,11 +336,10 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
override fun visitField(declaration: IrField) { override fun visitField(declaration: IrField) {
super.visitField(declaration) super.visitField(declaration)
val descriptor = declaration.descriptor val descriptor = declaration
val dispatchReceiverParameter = descriptor.dispatchReceiverParameter val containingClass = descriptor.containingClass
if (dispatchReceiverParameter != null) { if (containingClass != null) {
val containingClass = dispatchReceiverParameter.containingDeclaration
val classDeclarations = this.classes[containingClass] ?: error(containingClass.toString()) val classDeclarations = this.classes[containingClass] ?: error(containingClass.toString())
val allFields = classDeclarations.fields val allFields = classDeclarations.fields
@@ -381,9 +363,9 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
override fun visitFunction(declaration: IrFunction) { override fun visitFunction(declaration: IrFunction) {
super.visitFunction(declaration) super.visitFunction(declaration)
if (!declaration.descriptor.kind.isReal) return if (!declaration.isReal) return
val descriptor = declaration.descriptor val descriptor = declaration
val llvmFunctionType = getLlvmFunctionType(descriptor) val llvmFunctionType = getLlvmFunctionType(descriptor)
if ((descriptor is ConstructorDescriptor && descriptor.getObjCInitMethod() != null)) { if ((descriptor is ConstructorDescriptor && descriptor.getObjCInitMethod() != null)) {
@@ -402,7 +384,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
} else { } else {
val symbolName = if (descriptor.isExported()) { val symbolName = if (descriptor.isExported()) {
descriptor.symbolName.also { descriptor.symbolName.also {
if (!MainFunctionDetector.isMain(descriptor)) { if (!descriptor.isMain()) {
assert(LLVMGetNamedFunction(context.llvm.llvmModule, it) == null) { it } assert(LLVMGetNamedFunction(context.llvm.llvmModule, it) == null) { it }
} else { } else {
// As a workaround, allow `main` functions to clash because frontend accepts this. // As a workaround, allow `main` functions to clash because frontend accepts this.
@@ -19,15 +19,12 @@ package org.jetbrains.kotlin.backend.konan.llvm
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.isExternalObjCClassMethod import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.constants.StringValue import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
internal class RTTIGenerator(override val context: Context) : ContextUtils { internal class RTTIGenerator(override val context: Context) : ContextUtils {
@@ -125,8 +122,8 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
val size = getInstanceSize(bodyType, className) val size = getInstanceSize(bodyType, className)
val superTypeOrAny = classDesc.getSuperClassOrAny() val superTypeOrAny = classDesc.getSuperClassNotAny() ?: context.ir.symbols.any.owner
val superType = if (KotlinBuiltIns.isAny(classDesc)) NullPointer(runtime.typeInfoType) val superType = if (classDesc.isAny()) NullPointer(runtime.typeInfoType)
else superTypeOrAny.typeInfoPtr else superTypeOrAny.typeInfoPtr
val interfaces = classDesc.implementedInterfaces.map { it.typeInfoPtr } val interfaces = classDesc.implementedInterfaces.map { it.typeInfoPtr }
@@ -236,14 +233,14 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
val size = 0 val size = 0
val superClass = context.builtIns.any val superClass = context.ir.symbols.any.owner
assert(superClass.implementedInterfaces.isEmpty()) assert(superClass.implementedInterfaces.isEmpty())
val interfaces = listOf(descriptor.typeInfoPtr) val interfaces = listOf(descriptor.typeInfoPtr)
val interfacesPtr = staticData.placeGlobalConstArray("", val interfacesPtr = staticData.placeGlobalConstArray("",
pointerType(runtime.typeInfoType), interfaces) pointerType(runtime.typeInfoType), interfaces)
assert(superClass.getMemberScope().getVariableNames().isEmpty()) assert(superClass.declarations.all { it !is IrProperty && it !is IrField })
val objOffsetsPtr = NullPointer(int32Type) val objOffsetsPtr = NullPointer(int32Type)
val objOffsetsCount = 0 val objOffsetsCount = 0
val fieldsPtr = NullPointer(runtime.fieldTableRecordType) val fieldsPtr = NullPointer(runtime.fieldTableRecordType)
@@ -295,18 +292,18 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
private fun getReflectionInfo(descriptor: ClassDescriptor): ReflectionInfo { private fun getReflectionInfo(descriptor: ClassDescriptor): ReflectionInfo {
// Use data from value class in type info for box class: // Use data from value class in type info for box class:
val descriptorForReflection = context.ir.symbols.valueClassToBox.entries val descriptorForReflection = context.ir.symbols.valueClassToBox.entries
.firstOrNull { it.value.descriptor == descriptor } .firstOrNull { it.value.owner == descriptor }
?.key ?: descriptor ?.key?.owner ?: descriptor
return if (DescriptorUtils.isAnonymousObject(descriptorForReflection)) { return if (descriptorForReflection.isAnonymousObject) {
ReflectionInfo(packageName = null, relativeName = null) ReflectionInfo(packageName = null, relativeName = null)
} else if (DescriptorUtils.isLocal(descriptorForReflection)) { } else if (descriptorForReflection.isLocal) {
ReflectionInfo(packageName = null, relativeName = descriptorForReflection.name.asString()) ReflectionInfo(packageName = null, relativeName = descriptorForReflection.name.asString())
} else { } else {
ReflectionInfo( ReflectionInfo(
packageName = descriptorForReflection.findPackage().fqName.asString(), packageName = descriptorForReflection.findPackage().fqName.asString(),
relativeName = descriptorForReflection.parentsWithSelf relativeName = generateSequence(descriptorForReflection, { it.parent as? ClassDescriptor })
.takeWhile { it is ClassDescriptor }.toList().reversed() .toList().reversed()
.joinToString(".") { it.name.asString() } .joinToString(".") { it.name.asString() }
) )
} }
@@ -186,5 +186,5 @@ internal class StaticData(override val context: Context): ContextUtils {
*/ */
internal fun StaticData.createImmutableBinaryBlob(value: IrConst<String>): LLVMValueRef { internal fun StaticData.createImmutableBinaryBlob(value: IrConst<String>): LLVMValueRef {
val args = value.value.map { Int8(it.toByte()).llvm } val args = value.value.map { Int8(it.toByte()).llvm }
return createKotlinArray(context.ir.symbols.immutableBinaryBlob.descriptor.defaultType, args) return createKotlinArray(context.ir.symbols.immutableBinaryBlob.owner, args)
} }
@@ -20,14 +20,14 @@ import llvm.LLVMLinkage
import llvm.LLVMSetLinkage import llvm.LLVMSetLinkage
import llvm.LLVMTypeRef import llvm.LLVMTypeRef
import llvm.LLVMValueRef import llvm.LLVMValueRef
import org.jetbrains.kotlin.backend.konan.descriptors.isUnit import org.jetbrains.kotlin.backend.konan.irasdescriptors.defaultType
import org.jetbrains.kotlin.backend.konan.irasdescriptors.fqNameSafe
import org.jetbrains.kotlin.backend.konan.irasdescriptors.llvmSymbolOrigin
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.expressions.IrConst import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeProjection import org.jetbrains.kotlin.types.TypeProjection
import org.jetbrains.kotlin.types.replace import org.jetbrains.kotlin.types.replace
@@ -43,12 +43,10 @@ private fun StaticData.arrayHeader(typeInfo: ConstPointer, length: Int): Struct
} }
internal fun StaticData.createKotlinStringLiteral(value: String): ConstPointer { internal fun StaticData.createKotlinStringLiteral(value: String): ConstPointer {
val type = context.builtIns.stringType
val name = "kstr:" + value.globalHashBase64 val name = "kstr:" + value.globalHashBase64
val elements = value.toCharArray().map(::Char16) val elements = value.toCharArray().map(::Char16)
val objRef = createKotlinArray(type, elements) val objRef = createKotlinArray(context.ir.symbols.string.owner, elements)
val res = createAlias(name, objRef) val res = createAlias(name, objRef)
LLVMSetLinkage(res.llvm, LLVMLinkage.LLVMWeakAnyLinkage) LLVMSetLinkage(res.llvm, LLVMLinkage.LLVMWeakAnyLinkage)
@@ -56,20 +54,13 @@ internal fun StaticData.createKotlinStringLiteral(value: String): ConstPointer {
return res return res
} }
private fun StaticData.createRef(type: KotlinType, objHeaderPtr: ConstPointer): ConstPointer { private fun StaticData.createRef(objHeaderPtr: ConstPointer) = objHeaderPtr.bitcast(kObjHeaderPtr)
val llvmType = getLLVMType(type)
return if (llvmType != objHeaderPtr.llvmType) {
objHeaderPtr.bitcast(llvmType)
} else {
objHeaderPtr
}
}
internal fun StaticData.createKotlinArray(arrayType: KotlinType, elements: List<LLVMValueRef>) = internal fun StaticData.createKotlinArray(arrayClass: IrClass, elements: List<LLVMValueRef>) =
createKotlinArray(arrayType, elements.map { constValue(it) }).llvm createKotlinArray(arrayClass, elements.map { constValue(it) }).llvm
internal fun StaticData.createKotlinArray(arrayType: KotlinType, elements: List<ConstValue>): ConstPointer { internal fun StaticData.createKotlinArray(arrayClass: IrClass, elements: List<ConstValue>): ConstPointer {
val typeInfo = arrayType.typeInfoPtr!! val typeInfo = arrayClass.typeInfoPtr
val bodyElementType: LLVMTypeRef = elements.firstOrNull()?.llvmType ?: int8Type val bodyElementType: LLVMTypeRef = elements.firstOrNull()?.llvmType ?: int8Type
// (use [0 x i8] as body if there are no elements) // (use [0 x i8] as body if there are no elements)
@@ -84,11 +75,11 @@ internal fun StaticData.createKotlinArray(arrayType: KotlinType, elements: List<
global.setInitializer(Struct(compositeType, arrayHeader, arrayBody)) global.setInitializer(Struct(compositeType, arrayHeader, arrayBody))
return createRef(arrayType, objHeaderPtr) return createRef(objHeaderPtr)
} }
internal fun StaticData.createKotlinObject(type: KotlinType, body: ConstValue): ConstPointer { internal fun StaticData.createKotlinObject(type: IrClass, body: ConstValue): ConstPointer {
val typeInfo = type.typeInfoPtr!! val typeInfo = type.typeInfoPtr
val compositeType = structType(runtime.objHeaderType, body.llvmType) val compositeType = structType(runtime.objHeaderType, body.llvmType)
@@ -99,7 +90,7 @@ internal fun StaticData.createKotlinObject(type: KotlinType, body: ConstValue):
global.setInitializer(Struct(compositeType, objHeader, body)) global.setInitializer(Struct(compositeType, objHeader, body))
return createRef(type, objHeaderPtr) return createRef(objHeaderPtr)
} }
private fun StaticData.getArrayListClass(): ClassDescriptor { private fun StaticData.getArrayListClass(): ClassDescriptor {
@@ -118,7 +109,7 @@ private fun StaticData.getArrayListClass(): ClassDescriptor {
* @param length value for `length: Int` field. * @param length value for `length: Int` field.
*/ */
internal fun StaticData.createArrayList(elementType: TypeProjection, array: ConstPointer, length: Int): ConstPointer { internal fun StaticData.createArrayList(elementType: TypeProjection, array: ConstPointer, length: Int): ConstPointer {
val arrayListClass = getArrayListClass() val arrayListClass = context.ir.symbols.arrayList.owner
// type is ArrayList<elementType>: // type is ArrayList<elementType>:
val type = arrayListClass.defaultType.replace(listOf(elementType)) val type = arrayListClass.defaultType.replace(listOf(elementType))
@@ -140,15 +131,13 @@ internal fun StaticData.createArrayList(elementType: TypeProjection, array: Cons
val body = Struct(*(sorted.values.toTypedArray())) val body = Struct(*(sorted.values.toTypedArray()))
return createKotlinObject(type, body) return createKotlinObject(arrayListClass, body)
} }
internal fun StaticData.createUnitInstance(descriptor: ClassDescriptor, internal fun StaticData.createUnitInstance(bodyType: LLVMTypeRef,
bodyType: LLVMTypeRef,
typeInfo: ConstPointer typeInfo: ConstPointer
): ConstPointer { ): ConstPointer {
assert (descriptor.isUnit())
assert (getStructElements(bodyType).isEmpty()) assert (getStructElements(bodyType).isEmpty())
val objHeader = objHeader(typeInfo) val objHeader = objHeader(typeInfo)
val global = this.placeGlobal(theUnitInstanceName, objHeader, isExported = true) val global = this.placeGlobal(theUnitInstanceName, objHeader, isExported = true)
@@ -157,7 +146,7 @@ internal fun StaticData.createUnitInstance(descriptor: ClassDescriptor,
internal val ContextUtils.theUnitInstanceRef: ConstPointer internal val ContextUtils.theUnitInstanceRef: ConstPointer
get() { get() {
val unitDescriptor = context.builtIns.unit val unitDescriptor = context.ir.symbols.unit.owner
return if (isExternal(unitDescriptor)) { return if (isExternal(unitDescriptor)) {
constPointer(importGlobal( constPointer(importGlobal(
theUnitInstanceName, theUnitInstanceName,
@@ -18,8 +18,9 @@ package org.jetbrains.kotlin.backend.konan.llvm
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -175,3 +176,9 @@ internal fun debugInfoParameterLocation(builder: DIBuilderRef?,
return VariableDebugLocation(localVariable = variableDeclaration!!, location = location, file = file, line = line) return VariableDebugLocation(localVariable = variableDeclaration!!, location = location, file = file, line = line)
} }
private val ValueDescriptor.type get() = when (this) {
is IrVariable -> this.type
is IrValueParameter -> this.type
else -> error(this)
}
@@ -19,10 +19,9 @@ package org.jetbrains.kotlin.backend.konan.llvm.objcexport
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.konan.descriptors.CurrentKonanModule import org.jetbrains.kotlin.backend.konan.descriptors.CurrentKonanModule
import org.jetbrains.kotlin.backend.konan.llvm.* import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.util.OperatorNameConventions
internal fun ObjCExportCodeGenerator.generateKotlinFunctionImpl(invokeMethod: FunctionDescriptor): ConstPointer { internal fun ObjCExportCodeGenerator.generateKotlinFunctionImpl(invokeMethod: FunctionDescriptor): ConstPointer {
// TODO: consider also overriding methods of `Any`. // TODO: consider also overriding methods of `Any`.
@@ -31,7 +30,7 @@ internal fun ObjCExportCodeGenerator.generateKotlinFunctionImpl(invokeMethod: Fu
val function = generateFunction( val function = generateFunction(
codegen, codegen,
codegen.getLlvmFunctionType(invokeMethod), codegen.getLlvmFunctionType(context.ir.get(invokeMethod)),
"invokeFunction$numberOfParameters" "invokeFunction$numberOfParameters"
) { ) {
val args = (0 until numberOfParameters).map { index -> kotlinReferenceToObjC(param(index + 1)) } val args = (0 until numberOfParameters).map { index -> kotlinReferenceToObjC(param(index + 1)) }
@@ -154,7 +153,10 @@ internal class BlockAdapterToFunctionGenerator(val objCExportCodeGenerator: ObjC
objCReferenceToKotlin(param(index), Lifetime.ARGUMENT) objCReferenceToKotlin(param(index), Lifetime.ARGUMENT)
} }
val callee = lookupVirtualImpl(kotlinFunction, context.builtIns.getInvokeDescriptor(numberOfParameters)) val invokeMethod = context.ir.symbols.functions[numberOfParameters].owner.declarations
.filterIsInstance<IrSimpleFunction>().single { it.name == OperatorNameConventions.INVOKE }
val callee = lookupVirtualImpl(kotlinFunction, invokeMethod)
val result = callFromBridge(callee, listOf(kotlinFunction) + args, Lifetime.ARGUMENT) val result = callFromBridge(callee, listOf(kotlinFunction) + args, Lifetime.ARGUMENT)
@@ -221,9 +223,3 @@ internal class BlockAdapterToFunctionGenerator(val objCExportCodeGenerator: ObjC
} }
} }
} }
private fun KotlinBuiltIns.getInvokeDescriptor(numberOfParameters: Int): FunctionDescriptor =
getFunction(numberOfParameters).unsubstitutedMemberScope.getContributedFunctions(
Name.identifier("invoke"),
NoLookupLocation.FROM_BACKEND
).single()
@@ -21,15 +21,17 @@ import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.backend.common.descriptors.allParameters import org.jetbrains.kotlin.backend.common.descriptors.allParameters
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass
import org.jetbrains.kotlin.backend.konan.llvm.* import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.llvm.objc.ObjCCodeGenerator import org.jetbrains.kotlin.backend.konan.llvm.objc.ObjCCodeGenerator
import org.jetbrains.kotlin.backend.konan.objcexport.* import org.jetbrains.kotlin.backend.konan.objcexport.*
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.OperatorNameConventions
internal class ObjCExportCodeGenerator( internal class ObjCExportCodeGenerator(
codegen: CodeGenerator, codegen: CodeGenerator,
@@ -153,7 +155,7 @@ internal class ObjCExportCodeGenerator(
val value = genValue(Lifetime.ARGUMENT) val value = genValue(Lifetime.ARGUMENT)
return callFromBridge(conversion.descriptor.llvmFunction, listOf(value), resultLifetime) return callFromBridge(conversion.owner.llvmFunction, listOf(value), resultLifetime)
} }
internal fun emitRtti( internal fun emitRtti(
@@ -329,15 +331,16 @@ private fun ObjCExportCodeGenerator.setObjCExportTypeInfo(
val writableTypeInfoType = runtime.writableTypeInfoType!! val writableTypeInfoType = runtime.writableTypeInfoType!!
val writableTypeInfoValue = Struct(writableTypeInfoType, objCExportAddition) val writableTypeInfoValue = Struct(writableTypeInfoType, objCExportAddition)
val global = if (codegen.isExternal(descriptor)) { val irClass = context.ir.get(descriptor)
val global = if (codegen.isExternal(irClass)) {
// Note: this global replaces the external one with common linkage. // Note: this global replaces the external one with common linkage.
staticData.createGlobal( staticData.createGlobal(
writableTypeInfoType, writableTypeInfoType,
descriptor.writableTypeInfoSymbolName, irClass.writableTypeInfoSymbolName,
isExported = true isExported = true
) )
} else { } else {
context.llvmDeclarations.forClass(descriptor).writableTypeInfoGlobal!!.also { context.llvmDeclarations.forClass(irClass).writableTypeInfoGlobal!!.also {
it.setLinkage(LLVMLinkage.LLVMExternalLinkage) it.setLinkage(LLVMLinkage.LLVMExternalLinkage)
} }
} }
@@ -356,7 +359,7 @@ private fun ObjCExportCodeGenerator.emitBoxConverter(objCValueType: ObjCValueTyp
val name = "${valueType.classFqName.shortName()}To${objCValueType.nsNumberName}" val name = "${valueType.classFqName.shortName()}To${objCValueType.nsNumberName}"
val converter = generateFunction(codegen, kotlinToObjCFunctionType, name) { val converter = generateFunction(codegen, kotlinToObjCFunctionType, name) {
val unboxFunction = symbols.getUnboxFunction(valueType).descriptor.llvmFunction val unboxFunction = symbols.getUnboxFunction(valueType).owner.llvmFunction
val kotlinValue = callFromBridge( val kotlinValue = callFromBridge(
unboxFunction, unboxFunction,
listOf(param(0)), listOf(param(0)),
@@ -385,15 +388,14 @@ private fun ObjCExportCodeGenerator.emitFunctionConverters() {
} }
private fun ObjCExportCodeGenerator.generateKotlinFunctionAdapterToBlock(numberOfParameters: Int): ConstPointer { private fun ObjCExportCodeGenerator.generateKotlinFunctionAdapterToBlock(numberOfParameters: Int): ConstPointer {
val interfaceDescriptor = codegen.context.builtIns.getFunction(numberOfParameters) val irInterface = context.ir.symbols.functions[numberOfParameters].owner
val invokeMethod = interfaceDescriptor.unsubstitutedMemberScope.getContributedFunctions( val invokeMethod = irInterface.declarations.filterIsInstance<IrSimpleFunction>()
Name.identifier("invoke"), NoLookupLocation.FROM_BACKEND .single { it.name == OperatorNameConventions.INVOKE }
).single()
val invokeImpl = generateKotlinFunctionImpl(invokeMethod) val invokeImpl = generateKotlinFunctionImpl(invokeMethod.descriptor)
return rttiGenerator.generateSyntheticInterfaceImpl( return rttiGenerator.generateSyntheticInterfaceImpl(
interfaceDescriptor, irInterface,
mapOf(invokeMethod to invokeImpl) mapOf(invokeMethod to invokeImpl)
) )
} }
@@ -414,7 +416,7 @@ private fun ObjCExportCodeGenerator.emitKotlinFunctionAdaptersToBlock() {
private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() { private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() {
setObjCExportTypeInfo( setObjCExportTypeInfo(
context.builtIns.string, context.builtIns.string,
constPointer(codegen.llvmFunction(context.interopBuiltIns.CreateNSStringFromKString)) constPointer(codegen.llvmFunction(context.ir.symbols.interopCreateNSStringFromKString.owner))
) )
setObjCExportTypeInfo( setObjCExportTypeInfo(
@@ -495,10 +497,11 @@ private fun ObjCExportCodeGenerator.generateObjCImp(
} }
} }
val targetIr = context.ir.get(target)
val llvmTarget = if (!isVirtual) { val llvmTarget = if (!isVirtual) {
codegen.llvmFunction(target) codegen.llvmFunction(targetIr)
} else { } else {
lookupVirtualImpl(args.first(), target) lookupVirtualImpl(args.first(), targetIr)
} }
val targetResult = callFromBridge(llvmTarget, args, Lifetime.ARGUMENT) val targetResult = callFromBridge(llvmTarget, args, Lifetime.ARGUMENT)
@@ -533,13 +536,15 @@ private fun ObjCExportCodeGenerator.generateObjCImpForArrayConstructor(
objCToKotlin(param(index + 2), typeBridge, Lifetime.ARGUMENT) objCToKotlin(param(index + 2), typeBridge, Lifetime.ARGUMENT)
} }
val targetIr = context.ir.get(target)
val arrayInstance = callFromBridge( val arrayInstance = callFromBridge(
context.llvm.allocArrayFunction, context.llvm.allocArrayFunction,
listOf(target.constructedClass.llvmTypeInfoPtr, kotlinValueArgs.first()), listOf((targetIr as IrConstructor).constructedClass.llvmTypeInfoPtr, kotlinValueArgs.first()),
resultLifetime = Lifetime.ARGUMENT resultLifetime = Lifetime.ARGUMENT
) )
callFromBridge( callFromBridge(
target.llvmFunction, targetIr.llvmFunction,
listOf(arrayInstance) + kotlinValueArgs listOf(arrayInstance) + kotlinValueArgs
) )
@@ -564,7 +569,7 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
val objcMsgSend = msgSender(objCFunctionType(methodBridge)) val objcMsgSend = msgSender(objCFunctionType(methodBridge))
val functionType = codegen.getLlvmFunctionType(descriptor) val functionType = codegen.getLlvmFunctionType(context.ir.get(descriptor))
val result = generateFunction(codegen, functionType, "") { val result = generateFunction(codegen, functionType, "") {
val args = mutableListOf<LLVMValueRef>() val args = mutableListOf<LLVMValueRef>()
@@ -689,7 +694,8 @@ private fun ObjCExportCodeGenerator.vtableIndex(descriptor: FunctionDescriptor):
return if (classDescriptor.isInterface) { return if (classDescriptor.isInterface) {
null null
} else { } else {
context.getVtableBuilder(classDescriptor).vtableIndex(descriptor) context.getVtableBuilder(context.ir.get(classDescriptor))
.vtableIndex(context.ir.get(descriptor) as IrSimpleFunction)
} }
} }
@@ -761,12 +767,12 @@ private fun ObjCExportCodeGenerator.createTypeAdapter(
inherited.forEach { inherited.forEach {
presentVtableBridges += vtableIndex(it) presentVtableBridges += vtableIndex(it)
presentMethodTableBridges += it.functionName presentMethodTableBridges += context.ir.get(it).functionName
} }
uninherited.forEach { uninherited.forEach {
val vtableIndex = vtableIndex(it) val vtableIndex = vtableIndex(it)
val functionName = it.functionName val functionName = context.ir.get(it).functionName
if (vtableIndex !in presentVtableBridges || functionName !in presentMethodTableBridges) { if (vtableIndex !in presentVtableBridges || functionName !in presentMethodTableBridges) {
presentVtableBridges += vtableIndex presentVtableBridges += vtableIndex
@@ -794,17 +800,18 @@ private fun ObjCExportCodeGenerator.createTypeAdapter(
.filter { mapper.isBaseMethod(it) && it.isOverridable } .filter { mapper.isBaseMethod(it) && it.isOverridable }
.map { createMethodVirtualAdapter(it) } .map { createMethodVirtualAdapter(it) }
val typeInfo = constPointer(codegen.typeInfoValue(descriptor)) val irClass = context.ir.get(descriptor)
val typeInfo = constPointer(codegen.typeInfoValue(irClass))
val objCName = namer.getClassOrProtocolName(descriptor) val objCName = namer.getClassOrProtocolName(descriptor)
val vtableSize = if (descriptor.kind == ClassKind.INTERFACE) { val vtableSize = if (descriptor.kind == ClassKind.INTERFACE) {
-1 -1
} else { } else {
context.getVtableBuilder(descriptor).vtableEntries.size context.getVtableBuilder(irClass).vtableEntries.size
} }
val vtable = if (!descriptor.isInterface && !descriptor.typeInfoHasVtableAttached) { val vtable = if (!descriptor.isInterface && !irClass.typeInfoHasVtableAttached) {
staticData.placeGlobal("", rttiGenerator.vtable(descriptor)).also { staticData.placeGlobal("", rttiGenerator.vtable(irClass)).also {
it.setConstant(true) it.setConstant(true)
}.pointer.getElementPtr(0) }.pointer.getElementPtr(0)
} else { } else {
@@ -812,7 +819,7 @@ private fun ObjCExportCodeGenerator.createTypeAdapter(
} }
val methodTable = if (!descriptor.isInterface && descriptor.isAbstract()) { val methodTable = if (!descriptor.isInterface && descriptor.isAbstract()) {
rttiGenerator.methodTableRecords(descriptor) rttiGenerator.methodTableRecords(irClass)
} else { } else {
emptyList() emptyList()
} }
@@ -859,13 +866,16 @@ private fun ObjCExportCodeGenerator.createDirectAdapters(
val implementation = if (this.modality == Modality.ABSTRACT) { val implementation = if (this.modality == Modality.ABSTRACT) {
null null
} else { } else {
OverriddenFunctionDescriptor(this, base).getImplementation(context) OverriddenFunctionDescriptor(
context.ir.get(this) as IrSimpleFunction,
context.ir.get(base) as IrSimpleFunction
).getImplementation(context)
} }
DirectAdapterRequest(implementation, base) DirectAdapterRequest(implementation?.descriptor, base)
} }
val superClassMethod = method.overriddenDescriptors val superClassMethod = method.overriddenDescriptors
.atMostOne { !(it.containingDeclaration as ClassDescriptor).isInterface } .atMostOne { !(it.containingDeclaration as ClassDescriptor).isInterface }?.original
val inheritedAdapters = superClassMethod?.getAllRequiredDirectAdapters().orEmpty() val inheritedAdapters = superClassMethod?.getAllRequiredDirectAdapters().orEmpty()
val requiredAdapters = method.getAllRequiredDirectAdapters() val requiredAdapters = method.getAllRequiredDirectAdapters()
@@ -914,7 +924,7 @@ private fun ObjCExportCodeGenerator.createObjectInstanceAdapter(
return generateObjCToKotlinMethodAdapter(methodBridge, selector) { return generateObjCToKotlinMethodAdapter(methodBridge, selector) {
initRuntimeIfNeeded() // For instance methods it gets called when allocating. initRuntimeIfNeeded() // For instance methods it gets called when allocating.
val value = getObjectValue(descriptor, ExceptionHandler.Caller, locationInfo = null) val value = getObjectValue(context.ir.get(descriptor), ExceptionHandler.Caller, locationInfo = null)
ret(kotlinToObjC(value, ReferenceBridge)) ret(kotlinToObjC(value, ReferenceBridge))
} }
} }
@@ -930,7 +940,7 @@ private fun ObjCExportCodeGenerator.createEnumEntryAdapter(
return generateObjCToKotlinMethodAdapter(methodBridge, selector) { return generateObjCToKotlinMethodAdapter(methodBridge, selector) {
initRuntimeIfNeeded() // For instance methods it gets called when allocating. initRuntimeIfNeeded() // For instance methods it gets called when allocating.
val value = getEnumEntry(descriptor, ExceptionHandler.Caller) val value = getEnumEntry(context.ir.getEnumEntry(descriptor), ExceptionHandler.Caller)
ret(kotlinToObjC(value, ReferenceBridge)) ret(kotlinToObjC(value, ReferenceBridge))
} }
} }
@@ -35,9 +35,10 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.util.createParameterDeclarations import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.simpleFunctions
import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.util.type
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
@@ -48,7 +49,7 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain
val interop = context.interopBuiltIns val interop = context.interopBuiltIns
val symbols = context.ir.symbols val symbols = context.ir.symbols
val nullableAnyType = context.builtIns.nullableAnyType val nullableAnyType = context.builtIns.nullableAnyType
var runtimeJobDescriptor: FunctionDescriptor? = null lateinit var runtimeJobFunction: IrSimpleFunction
override fun lower(irDeclarationContainer: IrDeclarationContainer) { override fun lower(irDeclarationContainer: IrDeclarationContainer) {
irDeclarationContainer.declarations.transformFlat { irDeclarationContainer.declarations.transformFlat {
@@ -68,10 +69,11 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain
return expression return expression
val job = expression.getValueArgument(3) as IrFunctionReference val job = expression.getValueArgument(3) as IrFunctionReference
val jobFunction = (job.symbol as IrSimpleFunctionSymbol).owner
val jobDescriptor = job.descriptor val jobDescriptor = job.descriptor
val arg = jobDescriptor.valueParameters[0] val arg = jobDescriptor.valueParameters[0]
if (runtimeJobDescriptor == null) { if (!::runtimeJobFunction.isInitialized) {
runtimeJobDescriptor = jobDescriptor.newCopyBuilder() val runtimeJobDescriptor = jobDescriptor.newCopyBuilder()
.setReturnType(nullableAnyType) .setReturnType(nullableAnyType)
.setValueParameters(listOf(ValueParameterDescriptorImpl( .setValueParameters(listOf(ValueParameterDescriptorImpl(
containingDeclaration = jobDescriptor, containingDeclaration = jobDescriptor,
@@ -87,8 +89,17 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain
source = arg.source source = arg.source
))) )))
.build()!! .build()!!
runtimeJobFunction = IrFunctionImpl(
jobFunction.startOffset,
jobFunction.endOffset,
IrDeclarationOrigin.DEFINED,
runtimeJobDescriptor
).also {
it.createParameterDeclarations()
}
} }
val overriddenJobDescriptor = OverriddenFunctionDescriptor(jobDescriptor, runtimeJobDescriptor!!) val overriddenJobDescriptor = OverriddenFunctionDescriptor(jobFunction, runtimeJobFunction)
if (!overriddenJobDescriptor.needBridge) return expression if (!overriddenJobDescriptor.needBridge) return expression
val bridge = context.buildBridge( val bridge = context.buildBridge(
@@ -115,22 +126,9 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain
internal class BridgesBuilding(val context: Context) : ClassLoweringPass { internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
override fun lower(irClass: IrClass) { override fun lower(irClass: IrClass) {
val functions = mutableSetOf<FunctionDescriptor?>() val builtBridges = mutableSetOf<IrSimpleFunction>()
irClass.declarations.forEach {
when (it) {
is IrFunction -> functions.add(it.descriptor)
is IrProperty -> {
functions.add(it.getter?.descriptor)
functions.add(it.setter?.descriptor)
}
}
}
irClass.descriptor.contributedMethods.forEach { functions.add(it) } irClass.simpleFunctions()
val builtBridges = mutableSetOf<FunctionDescriptor>()
functions.filterNotNull()
.filterNot { it.modality == Modality.ABSTRACT }
.forEach { function -> .forEach { function ->
function.allOverriddenDescriptors function.allOverriddenDescriptors
.map { OverriddenFunctionDescriptor(function, it) } .map { OverriddenFunctionDescriptor(function, it) }
@@ -151,7 +149,7 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
?: return declaration ?: return declaration
val descriptor = declaration.descriptor val descriptor = declaration.descriptor
val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor) val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor)
if (typeSafeBarrierDescription == null || builtBridges.contains(descriptor)) if (typeSafeBarrierDescription == null || builtBridges.contains(declaration))
return declaration return declaration
val irBuilder = context.createIrBuilder(declaration.symbol, declaration.startOffset, declaration.endOffset) val irBuilder = context.createIrBuilder(declaration.symbol, declaration.startOffset, declaration.endOffset)
@@ -169,22 +167,13 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
startOffset = irClass.startOffset, startOffset = irClass.startOffset,
endOffset = irClass.endOffset, endOffset = irClass.endOffset,
descriptor = descriptor, descriptor = descriptor,
targetSymbol = irClass.findMember(descriptor.descriptor), // TODO: optimize. targetSymbol = descriptor.descriptor.symbol,
superQualifierSymbol = irClass.symbol) superQualifierSymbol = irClass.symbol)
) )
} }
} }
private fun IrClass.findMember(descriptor: FunctionDescriptor): IrFunctionSymbol { internal object DECLARATION_ORIGIN_BRIDGE_METHOD :
val functions = this.declarations.filterIsInstance<IrFunction>().map { it.symbol }
val propertyAccessors = this.declarations
.filterIsInstance<IrProperty>()
.flatMap { listOfNotNull(it.getter?.symbol, it.setter?.symbol) }
return (functions + propertyAccessors).single { it.descriptor == descriptor }
}
private object DECLARATION_ORIGIN_BRIDGE_METHOD :
IrDeclarationOriginImpl("BRIDGE_METHOD") IrDeclarationOriginImpl("BRIDGE_METHOD")
private fun IrBuilderWithScope.returnIfBadType(value: IrExpression, private fun IrBuilderWithScope.returnIfBadType(value: IrExpression,
@@ -220,17 +209,20 @@ private fun IrBlockBodyBuilder.buildTypeSafeBarrier(function: IrFunction,
private fun Context.buildBridge(startOffset: Int, endOffset: Int, private fun Context.buildBridge(startOffset: Int, endOffset: Int,
descriptor: OverriddenFunctionDescriptor, targetSymbol: IrFunctionSymbol, descriptor: OverriddenFunctionDescriptor, targetSymbol: IrFunctionSymbol,
superQualifierSymbol: IrClassSymbol? = null): IrFunctionImpl { superQualifierSymbol: IrClassSymbol? = null): IrFunction {
val bridgeDescriptor = specialDeclarationsFactory.getBridgeDescriptor(descriptor)
val bridge = IrFunctionImpl(startOffset, endOffset, DECLARATION_ORIGIN_BRIDGE_METHOD, val bridge = specialDeclarationsFactory.getBridgeDescriptor(descriptor)
bridgeDescriptor).apply { createParameterDeclarations() }
if (bridge.modality == Modality.ABSTRACT) {
return bridge
}
val irBuilder = createIrBuilder(bridge.symbol, startOffset, endOffset) val irBuilder = createIrBuilder(bridge.symbol, startOffset, endOffset)
bridge.body = irBuilder.irBlockBody(bridge) { bridge.body = irBuilder.irBlockBody(bridge) {
val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor.overriddenDescriptor) val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor.overriddenDescriptor.descriptor)
typeSafeBarrierDescription?.let { buildTypeSafeBarrier(bridge, descriptor.descriptor, it) } typeSafeBarrierDescription?.let { buildTypeSafeBarrier(bridge, descriptor.descriptor.descriptor, it) }
val delegatingCall = IrCallImpl(startOffset, endOffset, targetSymbol, descriptor.descriptor, val delegatingCall = IrCallImpl(startOffset, endOffset, targetSymbol, targetSymbol.descriptor,
superQualifierSymbol = superQualifierSymbol /* Call non-virtually */ superQualifierSymbol = superQualifierSymbol /* Call non-virtually */
).apply { ).apply {
bridge.dispatchReceiverParameter?.let { bridge.dispatchReceiverParameter?.let {
@@ -244,7 +236,7 @@ private fun Context.buildBridge(startOffset: Int, endOffset: Int,
} }
} }
if (KotlinBuiltIns.isUnitOrNullableUnit(bridgeDescriptor.returnType!!)) if (KotlinBuiltIns.isUnitOrNullableUnit(bridge.returnType))
+delegatingCall +delegatingCall
else else
+irReturn(delegatingCall) +irReturn(delegatingCall)
@@ -25,10 +25,9 @@ import org.jetbrains.kotlin.backend.common.descriptors.replace
import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.common.ir.createFakeOverrideDescriptor
import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.backend.common.pop import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.irasdescriptors.fqNameSafe
import org.jetbrains.kotlin.backend.konan.llvm.functionName import org.jetbrains.kotlin.backend.konan.llvm.functionName
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
@@ -54,11 +53,10 @@ import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
@@ -69,7 +67,7 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
private var functionReferenceCount = 0 private var functionReferenceCount = 0
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(object: IrElementTransformerVoidWithContext() { irFile.transform(object: IrElementTransformerVoidWithContext() {
private val stack = mutableListOf<IrElement>() private val stack = mutableListOf<IrElement>()
@@ -126,7 +124,12 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
return expression return expression
} }
val loweredFunctionReference = FunctionReferenceBuilder(currentScope!!.scope.scopeOwner, expression).build() val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().last()
val loweredFunctionReference = FunctionReferenceBuilder(
currentScope!!.scope.scopeOwner,
parent,
expression
).build()
val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset) val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset)
return irBuilder.irBlock(expression) { return irBuilder.irBlock(expression) {
+loweredFunctionReference.functionReferenceClass +loweredFunctionReference.functionReferenceClass
@@ -137,7 +140,7 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
} }
} }
} }
}) }, null)
} }
private class BuiltFunctionReference(val functionReferenceClass: IrClass, private class BuiltFunctionReference(val functionReferenceClass: IrClass,
@@ -154,6 +157,7 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
private val getContinuationSymbol = context.ir.symbols.getContinuation private val getContinuationSymbol = context.ir.symbols.getContinuation
private inner class FunctionReferenceBuilder(val containingDeclaration: DeclarationDescriptor, private inner class FunctionReferenceBuilder(val containingDeclaration: DeclarationDescriptor,
val parent: IrDeclarationParent,
val functionReference: IrFunctionReference) { val functionReference: IrFunctionReference) {
private val functionDescriptor = functionReference.descriptor private val functionDescriptor = functionReference.descriptor
@@ -176,12 +180,14 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
val superTypes = mutableListOf( val superTypes = mutableListOf(
kFunctionImplSymbol.owner.defaultType.replace(listOf(returnType)) kFunctionImplSymbol.owner.defaultType.replace(listOf(returnType))
) )
val superClasses = mutableListOf(kFunctionImplSymbol.owner)
val numberOfParameters = unboundFunctionParameters.size val numberOfParameters = unboundFunctionParameters.size
val functionClassDescriptor = context.reflectionTypes.getKFunction(numberOfParameters) val functionClassDescriptor = context.reflectionTypes.getKFunction(numberOfParameters)
val functionParameterTypes = unboundFunctionParameters.map { it.type } val functionParameterTypes = unboundFunctionParameters.map { it.type }
val functionClassTypeParameters = functionParameterTypes + returnType val functionClassTypeParameters = functionParameterTypes + returnType
superTypes += functionClassDescriptor.defaultType.replace(functionClassTypeParameters) superTypes += functionClassDescriptor.defaultType.replace(functionClassTypeParameters)
superClasses += context.ir.symbols.kFunctions[numberOfParameters].owner
var suspendFunctionClassDescriptor: ClassDescriptor? = null var suspendFunctionClassDescriptor: ClassDescriptor? = null
var suspendFunctionClassTypeParameters: List<KotlinType>? = null var suspendFunctionClassTypeParameters: List<KotlinType>? = null
@@ -192,9 +198,10 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
Name.identifier("SuspendFunction${numberOfParameters - 1}"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor Name.identifier("SuspendFunction${numberOfParameters - 1}"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) + lastParameterType.arguments.single().type suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) + lastParameterType.arguments.single().type
superTypes += suspendFunctionClassDescriptor.defaultType.replace(suspendFunctionClassTypeParameters) superTypes += suspendFunctionClassDescriptor.defaultType.replace(suspendFunctionClassTypeParameters)
superClasses += context.ir.symbols.suspendFunctions[numberOfParameters - 1].owner
} }
functionReferenceClassDescriptor = ClassDescriptorImpl( functionReferenceClassDescriptor = object : ClassDescriptorImpl(
/* containingDeclaration = */ containingDeclaration, /* containingDeclaration = */ containingDeclaration,
/* name = */ "${functionDescriptor.name}\$${functionReferenceCount++}".synthesizedName, /* name = */ "${functionDescriptor.name}\$${functionReferenceCount++}".synthesizedName,
/* modality = */ Modality.FINAL, /* modality = */ Modality.FINAL,
@@ -202,13 +209,16 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
/* superTypes = */ superTypes, /* superTypes = */ superTypes,
/* source = */ SourceElement.NO_SOURCE, /* source = */ SourceElement.NO_SOURCE,
/* isExternal = */ false /* isExternal = */ false
) ) {
override fun getVisibility() = Visibilities.PRIVATE
}
functionReferenceClass = IrClassImpl( functionReferenceClass = IrClassImpl(
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
descriptor = functionReferenceClassDescriptor descriptor = functionReferenceClassDescriptor
) )
functionReferenceClass.parent = this.parent
val constructorBuilder = createConstructorBuilder() val constructorBuilder = createConstructorBuilder()
@@ -222,33 +232,27 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
suspendInvokeMethodBuilder = createInvokeMethodBuilder(suspendInvokeFunctionDescriptor) suspendInvokeMethodBuilder = createInvokeMethodBuilder(suspendInvokeFunctionDescriptor)
} }
val inheritedKFunctionImpl = kFunctionImplSymbol.descriptor.unsubstitutedMemberScope val memberScope = stub<MemberScope>("callable reference class")
.getContributedDescriptors()
.map { it.createFakeOverrideDescriptor(functionReferenceClassDescriptor) }
.filterNotNull()
val contributedDescriptors = (
inheritedKFunctionImpl + invokeMethodBuilder.symbol.descriptor + suspendInvokeMethodBuilder?.symbol?.descriptor
).filterNotNull().toList()
functionReferenceClassDescriptor.initialize( functionReferenceClassDescriptor.initialize(
SimpleMemberScope(contributedDescriptors), setOf(constructorBuilder.symbol.descriptor), null) memberScope, setOf(constructorBuilder.symbol.descriptor), null)
functionReferenceClass.createParameterDeclarations() functionReferenceClass.createParameterDeclarations()
functionReferenceThis = functionReferenceClass.thisReceiver!!.symbol functionReferenceThis = functionReferenceClass.thisReceiver!!.symbol
functionReferenceClass.addFakeOverrides()
constructorBuilder.initialize() constructorBuilder.initialize()
functionReferenceClass.declarations.add(constructorBuilder.ir) functionReferenceClass.addChild(constructorBuilder.ir)
invokeMethodBuilder.initialize() invokeMethodBuilder.initialize()
functionReferenceClass.declarations.add(invokeMethodBuilder.ir) functionReferenceClass.addChild(invokeMethodBuilder.ir)
suspendInvokeMethodBuilder?.let { suspendInvokeMethodBuilder?.let {
it.initialize() it.initialize()
functionReferenceClass.declarations.add(it.ir) functionReferenceClass.addChild(it.ir)
} }
functionReferenceClass.setSuperSymbolsAndAddFakeOverrides(superClasses)
return BuiltFunctionReference(functionReferenceClass, constructorBuilder.ir) return BuiltFunctionReference(functionReferenceClass, constructorBuilder.ir)
} }
@@ -299,7 +303,7 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
IrConstKind.String, functionDescriptor.name.asString()) IrConstKind.String, functionDescriptor.name.asString())
putValueArgument(0, name) putValueArgument(0, name)
val fqName = IrConstImpl(startOffset, endOffset, context.builtIns.stringType, IrConstKind.String, val fqName = IrConstImpl(startOffset, endOffset, context.builtIns.stringType, IrConstKind.String,
functionDescriptor.fullName) (functionReference.symbol.owner as IrFunction).fullName)
putValueArgument(1, fqName) putValueArgument(1, fqName)
val bound = IrConstImpl.boolean(startOffset, endOffset, context.builtIns.booleanType, val bound = IrConstImpl.boolean(startOffset, endOffset, context.builtIns.booleanType,
boundFunctionParameters.isNotEmpty()) boundFunctionParameters.isNotEmpty())
@@ -318,17 +322,8 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
} }
} }
// TODO: what about private package level functions? private val IrFunction.fullName: String
private val DeclarationDescriptor.fullName: String get() = parent.fqNameSafe.child(Name.identifier(functionName)).asString()
get() {
return when (this) {
is PackageFragmentDescriptor -> fqNameSafe.asString()
is ClassDescriptor -> containingDeclaration.fullName + "." + fqNameSafe
is FunctionDescriptor -> containingDeclaration.fullName + "." + functionName
is PropertyDescriptor -> containingDeclaration.fullName + "." + fqNameSafe
else -> TODO("$this")
}
}
private fun createInvokeMethodBuilder(superFunctionDescriptor: FunctionDescriptor) private fun createInvokeMethodBuilder(superFunctionDescriptor: FunctionDescriptor)
= object : SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() { = object : SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
@@ -385,7 +380,10 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
val argument = val argument =
if (!unboundArgsSet.contains(it)) if (!unboundArgsSet.contains(it))
// Bound parameter - read from field. // Bound parameter - read from field.
irGetField(irGet(functionReferenceThis), argumentToPropertiesMap[it]!!) irGetField(
irGet(function.dispatchReceiverParameter!!.symbol),
argumentToPropertiesMap[it]!!
)
else { else {
if (ourSymbol.descriptor.isSuspend && unboundIndex == valueParameters.size) if (ourSymbol.descriptor.isSuspend && unboundIndex == valueParameters.size)
// For suspend functions the last argument is continuation and it is implicit. // For suspend functions the last argument is continuation and it is implicit.
@@ -420,7 +418,7 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
initialize() initialize()
} }
functionReferenceClass.declarations.add(propertyBuilder.ir) functionReferenceClass.addChild(propertyBuilder.ir)
return propertyBuilder.ir.backingField!!.symbol return propertyBuilder.ir.backingField!!.symbol
} }
@@ -16,10 +16,10 @@
package org.jetbrains.kotlin.backend.konan.lower package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.IrElementVisitorVoidWithContext import org.jetbrains.kotlin.backend.common.IrElementVisitorVoidWithContext
import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.* import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
@@ -46,9 +46,9 @@ import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.makeNullable import org.jetbrains.kotlin.types.typeUtil.makeNullable
class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor, internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor,
val parentDescriptor: DeclarationDescriptor, val parentDescriptor: DeclarationDescriptor,
val context: CommonBackendContext) { val context: Context) {
private val descriptorSubstituteMap: MutableMap<DeclarationDescriptor, DeclarationDescriptor> = mutableMapOf() private val descriptorSubstituteMap: MutableMap<DeclarationDescriptor, DeclarationDescriptor> = mutableMapOf()
private var typeSubstitutor: TypeSubstitutor? = null private var typeSubstitutor: TypeSubstitutor? = null
@@ -503,7 +503,9 @@ class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor,
origin = mapDeclarationOrigin(declaration.origin), origin = mapDeclarationOrigin(declaration.origin),
descriptor = mapFunctionDeclaration(declaration.descriptor), descriptor = mapFunctionDeclaration(declaration.descriptor),
body = declaration.body?.transform(this, null) body = declaration.body?.transform(this, null)
).transformParameters(declaration) ).also {
it.setOverrides(context.ir.symbols.symbolTable)
}.transformParameters(declaration)
//---------------------------------------------------------------------// //---------------------------------------------------------------------//
@@ -55,7 +55,11 @@ open class DefaultArgumentStubGenerator constructor(val context: CommonBackendCo
override fun lower(irDeclarationContainer: IrDeclarationContainer) { override fun lower(irDeclarationContainer: IrDeclarationContainer) {
irDeclarationContainer.declarations.transformFlat { memberDeclaration -> irDeclarationContainer.declarations.transformFlat { memberDeclaration ->
if (memberDeclaration is IrFunction) if (memberDeclaration is IrFunction)
lower(memberDeclaration) lower(memberDeclaration).also { functions ->
functions.forEach {
it.parent = irDeclarationContainer
}
}
else else
null null
} }
@@ -78,12 +82,18 @@ open class DefaultArgumentStubGenerator constructor(val context: CommonBackendCo
functionDescriptor.overriddenDescriptors.forEach { context.log{"DEFAULT-REPLACER: $it"} } functionDescriptor.overriddenDescriptors.forEach { context.log{"DEFAULT-REPLACER: $it"} }
if (bodies.isNotEmpty()) { if (bodies.isNotEmpty()) {
val newIrFunction = functionDescriptor.generateDefaultsFunction(context) val newIrFunction = functionDescriptor.generateDefaultsFunction(context)
newIrFunction.parent = irFunction.parent
val descriptor = newIrFunction.descriptor val descriptor = newIrFunction.descriptor
log { "$functionDescriptor -> $descriptor" } log { "$functionDescriptor -> $descriptor" }
val builder = context.createIrBuilder(newIrFunction.symbol) val builder = context.createIrBuilder(newIrFunction.symbol)
val body = builder.irBlockBody(irFunction) { newIrFunction.body = builder.irBlockBody(newIrFunction) {
val params = mutableListOf<IrVariableSymbol>() val params = mutableListOf<IrVariableSymbol>()
val variables = mutableMapOf<ValueDescriptor, IrValueSymbol>() val variables = mutableMapOf<ValueDescriptor, IrValueSymbol>()
irFunction.dispatchReceiverParameter?.let {
variables[it.descriptor] = newIrFunction.dispatchReceiverParameter!!.symbol
}
if (descriptor.extensionReceiverParameter != null) { if (descriptor.extensionReceiverParameter != null) {
variables[functionDescriptor.extensionReceiverParameter!!] = variables[functionDescriptor.extensionReceiverParameter!!] =
newIrFunction.extensionReceiverParameter!!.symbol newIrFunction.extensionReceiverParameter!!.symbol
@@ -157,20 +167,8 @@ open class DefaultArgumentStubGenerator constructor(val context: CommonBackendCo
irFunction.valueParameters.forEach { irFunction.valueParameters.forEach {
it.defaultValue = null it.defaultValue = null
} }
return if (functionDescriptor is ClassConstructorDescriptor)
listOf(irFunction, IrConstructorImpl( return listOf(irFunction, newIrFunction)
startOffset = irFunction.startOffset,
endOffset = irFunction.endOffset,
descriptor = descriptor as ClassConstructorDescriptor,
origin = DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER,
body = body).apply { createParameterDeclarations() })
else
listOf(irFunction, IrFunctionImpl(
startOffset = irFunction.startOffset,
endOffset = irFunction.endOffset,
descriptor = descriptor,
origin = DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER,
body = body).apply { createParameterDeclarations() })
} }
return listOf(irFunction) return listOf(irFunction)
} }
@@ -283,13 +281,24 @@ class DefaultParameterInjector constructor(val context: CommonBackendContext): B
} }
} }
private fun parametersForCall(expression: IrMemberAccessExpression): Pair<IrFunctionSymbol, List<Pair<ValueParameterDescriptor, IrExpression?>>> { private fun IrFunction.findSuperMethodWithDefaultArguments(): IrFunction? {
val descriptor = expression.descriptor as FunctionDescriptor if (!this.descriptor.needsDefaultArgumentsLowering) return null
val keyDescriptor = if (DescriptorUtils.isOverride(descriptor))
DescriptorUtils.getAllOverriddenDescriptors(descriptor).first { it.needsDefaultArgumentsLowering } if (this !is IrSimpleFunction) return this
else
descriptor.original this.overriddenSymbols.forEach {
it.owner.findSuperMethodWithDefaultArguments()?.let { return it }
}
return this
}
private fun parametersForCall(expression: IrFunctionAccessExpression): Pair<IrFunctionSymbol, List<Pair<ValueParameterDescriptor, IrExpression?>>> {
val descriptor = expression.descriptor
val keyFunction = (expression.symbol.owner as IrFunction).findSuperMethodWithDefaultArguments()!!
val keyDescriptor = keyFunction.descriptor
val realFunction = keyDescriptor.generateDefaultsFunction(context) val realFunction = keyDescriptor.generateDefaultsFunction(context)
realFunction.parent = keyFunction.parent
val realDescriptor = realFunction.descriptor val realDescriptor = realFunction.descriptor
log { "$descriptor -> $realDescriptor" } log { "$descriptor -> $realDescriptor" }
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.ir.expressions.IrLocalDelegatedPropertyReference
import org.jetbrains.kotlin.ir.expressions.IrPropertyReference import org.jetbrains.kotlin.ir.expressions.IrPropertyReference
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.util.addChild
import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.functions import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -120,16 +121,14 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
declaration.transformChildrenVoid(this) declaration.transformChildrenVoid(this)
val initializer = declaration.delegate.initializer!! val initializer = declaration.delegate.initializer!!
return IrVariableImpl(declaration.startOffset, declaration.endOffset, declaration.delegate.initializer = IrBlockImpl(initializer.startOffset, initializer.endOffset, initializer.type, null,
declaration.origin, declaration.delegate.descriptor, listOf(
IrBlockImpl(initializer.startOffset, initializer.endOffset, initializer.type, null, declaration.getter,
listOf( declaration.setter,
declaration.getter, initializer
declaration.setter, ).filterNotNull())
initializer
).filterNotNull())
)
return declaration.delegate
} }
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression { override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
@@ -191,7 +190,7 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
if (kProperties.isNotEmpty()) { if (kProperties.isNotEmpty()) {
val initializers = kProperties.values.sortedBy { it.second }.map { it.first } val initializers = kProperties.values.sortedBy { it.second }.map { it.first }
// TODO: move to object for lazy initialization. // TODO: move to object for lazy initialization.
irFile.declarations.add(0, kPropertiesField.apply { irFile.addChild(kPropertiesField.apply {
initializer = IrExpressionBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, initializer = IrExpressionBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
context.createArrayOfExpression(kPropertyImplType, initializers, UNDEFINED_OFFSET, UNDEFINED_OFFSET)) context.createArrayOfExpression(kPropertyImplType, initializers, UNDEFINED_OFFSET, UNDEFINED_OFFSET))
}) })
@@ -19,13 +19,11 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.deepCopyWithVariables import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope
import org.jetbrains.kotlin.backend.common.runOnFilePostfix import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.backend.jvm.descriptors.createValueParameter import org.jetbrains.kotlin.backend.jvm.descriptors.createValueParameter
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.DECLARATION_ORIGIN_ENUM import org.jetbrains.kotlin.backend.konan.DECLARATION_ORIGIN_ENUM
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.common.ir.createFakeOverrideDescriptor
import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor
import org.jetbrains.kotlin.backend.common.ir.createArrayOfExpression import org.jetbrains.kotlin.backend.common.ir.createArrayOfExpression
import org.jetbrains.kotlin.backend.common.ir.createSimpleDelegatingConstructorDescriptor import org.jetbrains.kotlin.backend.common.ir.createSimpleDelegatingConstructorDescriptor
@@ -43,6 +41,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.TypeProjectionImpl import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.types.TypeSubstitutor
@@ -187,7 +186,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val defaultClass = createDefaultClassForEnumEntries() val defaultClass = createDefaultClassForEnumEntries()
lowerEnumClassBody() lowerEnumClassBody()
if (defaultClass != null) if (defaultClass != null)
irClass.declarations.add(defaultClass) irClass.addChild(defaultClass)
createImplObject() createImplObject()
} }
@@ -275,15 +274,11 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
} }
} }
val contributedDescriptors = irClass.descriptor.unsubstitutedMemberScope val memberScope = stub<MemberScope>("enum default class")
.getContributedDescriptors() defaultClassDescriptor.initialize(memberScope, constructors, null)
.map { it.createFakeOverrideDescriptor(defaultClassDescriptor) }
.filterNotNull()
.toList()
defaultClassDescriptor.initialize(SimpleMemberScope(contributedDescriptors), constructors, null)
defaultClass.createParameterDeclarations() defaultClass.createParameterDeclarations()
defaultClass.addFakeOverrides() defaultClass.setSuperSymbolsAndAddFakeOverrides(listOf(irClass))
return defaultClass return defaultClass
} }
@@ -325,10 +320,10 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
constructorOfAny, implObject.descriptor.constructors.single(), constructorOfAny, implObject.descriptor.constructors.single(),
DECLARATION_ORIGIN_ENUM) DECLARATION_ORIGIN_ENUM)
implObject.declarations.add(createSyntheticValuesPropertyDeclaration(enumEntries)) implObject.addChild(createSyntheticValuesPropertyDeclaration(enumEntries))
implObject.declarations.add(createValuesPropertyInitializer(enumEntries)) implObject.addChild(createValuesPropertyInitializer(enumEntries))
irClass.declarations.add(implObject) irClass.addChild(implObject)
} }
private val genericCreateUninitializedInstanceSymbol = context.ir.symbols.createUninitializedInstance private val genericCreateUninitializedInstanceSymbol = context.ir.symbols.createUninitializedInstance
@@ -363,7 +358,9 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
getter.body = IrBlockBodyImpl(startOffset, endOffset, listOf(returnStatement)) getter.body = IrBlockBodyImpl(startOffset, endOffset, listOf(returnStatement))
return IrPropertyImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, return IrPropertyImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM,
false, loweredEnum.valuesField.descriptor, irField, getter, null) false, loweredEnum.valuesField.descriptor, irField, getter, null).also {
it.parent = loweredEnum.implObject
}
} }
private val initInstanceSymbol = context.ir.symbols.initInstance private val initInstanceSymbol = context.ir.symbols.initInstance
@@ -432,6 +429,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
loweredConstructorDescriptor, loweredConstructorDescriptor,
enumConstructor.body!! // will be transformed later enumConstructor.body!! // will be transformed later
) )
loweredEnumConstructor.parent = enumConstructor.parent
loweredEnumConstructors[constructorDescriptor] = loweredEnumConstructor loweredEnumConstructors[constructorDescriptor] = loweredEnumConstructor
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.getDefault import org.jetbrains.kotlin.ir.declarations.getDefault
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.createValueSymbol import org.jetbrains.kotlin.ir.symbols.impl.createValueSymbol
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -133,6 +134,8 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
typeSubstitutor = createTypeSubstitutor(callee) // Type parameters will be substituted with type arguments. typeSubstitutor = createTypeSubstitutor(callee) // Type parameters will be substituted with type arguments.
) as IrFunction ) as IrFunction
val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl(copyFunctionDeclaration.descriptor.original)
val evaluationStatements = evaluateArguments(callee, copyFunctionDeclaration) // And list of evaluation statements. val evaluationStatements = evaluateArguments(callee, copyFunctionDeclaration) // And list of evaluation statements.
val statements = (copyFunctionDeclaration.body as IrBlockBody).statements // IR statements from function copy. val statements = (copyFunctionDeclaration.body as IrBlockBody).statements // IR statements from function copy.
@@ -142,7 +145,7 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
val descriptor = caller.descriptor.original val descriptor = caller.descriptor.original
if (descriptor.isInlineConstructor) { if (descriptor.isInlineConstructor) {
val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall
val irBuilder = context.createIrBuilder(copyFunctionDeclaration.symbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
irBuilder.run { irBuilder.run {
val constructorDescriptor = delegatingConstructorCall.descriptor.original val constructorDescriptor = delegatingConstructorCall.descriptor.original
val constructorCall = irCall(delegatingConstructorCall.symbol, val constructorCall = irCall(delegatingConstructorCall.symbol,
@@ -166,7 +169,7 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
type = returnType, type = returnType,
descriptor = copyFunctionDeclaration.descriptor.original, symbol = irReturnableBlockSymbol,
origin = null, origin = null,
statements = statements, statements = statements,
sourceFileName = sourceFileName sourceFileName = sourceFileName
@@ -28,12 +28,10 @@ import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.IrBlockBody import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.util.addChild
import org.jetbrains.kotlin.ir.util.createParameterDeclarations import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
@@ -118,7 +116,23 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
initializer.createParameterDeclarations() initializer.createParameterDeclarations()
irClass.declarations.add(initializer) initializers.forEach {
it.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
if (expression.symbol == irClass.thisReceiver!!.symbol) {
return IrGetValueImpl(
expression.startOffset,
expression.endOffset,
initializer.dispatchReceiverParameter!!.symbol
)
} else {
return expression
}
}
})
}
irClass.addChild(initializer)
return initializer.symbol return initializer.symbol
} }
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrBlockBody import org.jetbrains.kotlin.ir.expressions.IrBlockBody
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetValue import org.jetbrains.kotlin.ir.expressions.IrGetValue
@@ -31,6 +32,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.util.addChild
import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -57,7 +59,7 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
private fun createOuterThisField() { private fun createOuterThisField() {
val field = context.specialDeclarationsFactory.getOuterThisField(classDescriptor) val field = context.specialDeclarationsFactory.getOuterThisField(classDescriptor)
outerThisFieldSymbol = field.symbol outerThisFieldSymbol = field.symbol
irClass.declarations.add(field) irClass.addChild(field)
} }
private fun lowerConstructors() { private fun lowerConstructors() {
@@ -109,7 +111,16 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
var innerClass: ClassDescriptor var innerClass: ClassDescriptor
if (constructorSymbol == null || constructorSymbol.descriptor.constructedClass != classDescriptor) { if (constructorSymbol == null || constructorSymbol.descriptor.constructedClass != classDescriptor) {
innerClass = classDescriptor innerClass = classDescriptor
irThis = IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol, origin) val currentIrFunction = currentFunction!!.scope.scopeOwnerSymbol.owner as IrFunction
val currentFunctionReceiver = currentIrFunction.dispatchReceiverParameter
val thisSymbol = if (currentFunctionReceiver?.descriptor == irClass.thisReceiver!!.descriptor) {
currentFunctionReceiver
} else {
irClass.thisReceiver!!
}.symbol
irThis = IrGetValueImpl(startOffset, endOffset, thisSymbol, origin)
} else { } else {
// For constructor we have outer class as dispatchReceiverParameter. // For constructor we have outer class as dispatchReceiverParameter.
innerClass = DescriptorUtils.getContainingClass(classDescriptor) ?: innerClass = DescriptorUtils.getContainingClass(classDescriptor) ?:
@@ -123,7 +123,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
else -> null else -> null
} }
}.let { irClass.declarations.addAll(it) } }.let { irClass.addChildren(it) }
if (irClass.descriptor.annotations.hasAnnotation(interop.exportObjCClass.fqNameSafe)) { if (irClass.descriptor.annotations.hasAnnotation(interop.exportObjCClass.fqNameSafe)) {
val irBuilder = context.createIrBuilder(currentFile.symbol).at(irClass) val irBuilder = context.createIrBuilder(currentFile.symbol).at(irClass)
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.util.addChild
import org.jetbrains.kotlin.ir.util.createParameterDeclarations import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.ir.visitors.*
@@ -144,6 +145,17 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
"LocalClassContext for ${descriptor}" "LocalClassContext for ${descriptor}"
} }
private class LocalClassMemberContext(val member: IrFunction, val classContext: LocalClassContext) : LocalContext() {
override fun irGet(startOffset: Int, endOffset: Int, descriptor: ValueDescriptor): IrExpression? {
val field = classContext.capturedValueToField[descriptor] ?: return null
return IrGetFieldImpl(startOffset, endOffset, field.symbol,
receiver = IrGetValueImpl(startOffset, endOffset, member.dispatchReceiverParameter!!.symbol)
)
}
}
private inner class LocalDeclarationsTransformer(val memberDeclaration: IrDeclaration) { private inner class LocalDeclarationsTransformer(val memberDeclaration: IrDeclaration) {
val localFunctions: MutableMap<FunctionDescriptor, LocalFunctionContext> = LinkedHashMap() val localFunctions: MutableMap<FunctionDescriptor, LocalFunctionContext> = LinkedHashMap()
val localClasses: MutableMap<ClassDescriptor, LocalClassContext> = LinkedHashMap() val localClasses: MutableMap<ClassDescriptor, LocalClassContext> = LinkedHashMap()
@@ -169,6 +181,7 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
rewriteDeclarations() rewriteDeclarations()
val result = collectRewrittenDeclarations() val result = collectRewrittenDeclarations()
result.forEach { it.parent = memberDeclaration.parent }
return result return result
} }
@@ -209,7 +222,14 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
// Replace local function definition with an empty composite. // Replace local function definition with an empty composite.
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType) return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType)
} else { } else {
return super.visitFunction(declaration) if (localContext is LocalClassContext && declaration.parent == localContext.declaration) {
return declaration.apply {
val classMemberLocalContext = LocalClassMemberContext(declaration, localContext)
transformChildrenVoid(FunctionBodiesRewriter(classMemberLocalContext))
}
} else {
return super.visitFunction(declaration)
}
} }
} }
@@ -219,6 +239,7 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
val constructorContext = localClassConstructors[declaration.descriptor] val constructorContext = localClassConstructors[declaration.descriptor]
if (constructorContext != null) { if (constructorContext != null) {
return constructorContext.transformedDeclaration.apply { return constructorContext.transformedDeclaration.apply {
this.parent = declaration.parent
this.body = declaration.body!! this.body = declaration.body!!
declaration.descriptor.valueParameters.filter { it.declaresDefaultValue() }.forEach { argument -> declaration.descriptor.valueParameters.filter { it.declaresDefaultValue() }.forEach { argument ->
@@ -361,7 +382,7 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
localClassContext.capturedValueToField.forEach { capturedValue, field -> localClassContext.capturedValueToField.forEach { capturedValue, field ->
val startOffset = irClass.startOffset val startOffset = irClass.startOffset
val endOffset = irClass.endOffset val endOffset = irClass.endOffset
irClass.declarations.add(field) irClass.addChild(field)
for (constructorContext in constructorsCallingSuper) { for (constructorContext in constructorsCallingSuper) {
val blockBody = constructorContext.declaration.body as? IrBlockBody val blockBody = constructorContext.declaration.body as? IrBlockBody
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters
import org.jetbrains.kotlin.backend.common.descriptors.getFunction import org.jetbrains.kotlin.backend.common.descriptors.getFunction
import org.jetbrains.kotlin.backend.common.descriptors.replace import org.jetbrains.kotlin.backend.common.descriptors.replace
import org.jetbrains.kotlin.backend.common.ir.createFakeOverrideDescriptor
import org.jetbrains.kotlin.backend.common.ir.createOverriddenDescriptor import org.jetbrains.kotlin.backend.common.ir.createOverriddenDescriptor
import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
@@ -56,6 +55,7 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
@@ -301,6 +301,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
fun build(): BuiltCoroutine { fun build(): BuiltCoroutine {
val superTypes = mutableListOf<KotlinType>(coroutineImplClassDescriptor.defaultType) val superTypes = mutableListOf<KotlinType>(coroutineImplClassDescriptor.defaultType)
val superClasses = mutableListOf<IrClass>(coroutineImplSymbol.owner)
var suspendFunctionClassDescriptor: ClassDescriptor? = null var suspendFunctionClassDescriptor: ClassDescriptor? = null
var functionClassDescriptor: ClassDescriptor? = null var functionClassDescriptor: ClassDescriptor? = null
var suspendFunctionClassTypeArguments: List<KotlinType>? = null var suspendFunctionClassTypeArguments: List<KotlinType>? = null
@@ -313,12 +314,14 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
val unboundParameterTypes = unboundFunctionParameters.map { it.type } val unboundParameterTypes = unboundFunctionParameters.map { it.type }
suspendFunctionClassTypeArguments = unboundParameterTypes + irFunction.descriptor.returnType!! suspendFunctionClassTypeArguments = unboundParameterTypes + irFunction.descriptor.returnType!!
superTypes += suspendFunctionClassDescriptor.defaultType.replace(suspendFunctionClassTypeArguments) superTypes += suspendFunctionClassDescriptor.defaultType.replace(suspendFunctionClassTypeArguments)
superClasses += context.ir.symbols.suspendFunctions[numberOfParameters].owner
functionClassDescriptor = kotlinPackageScope.getContributedClassifier( functionClassDescriptor = kotlinPackageScope.getContributedClassifier(
Name.identifier("Function${numberOfParameters + 1}"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor Name.identifier("Function${numberOfParameters + 1}"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
val continuationType = continuationClassDescriptor.defaultType.replace(listOf(irFunction.descriptor.returnType!!)) val continuationType = continuationClassDescriptor.defaultType.replace(listOf(irFunction.descriptor.returnType!!))
functionClassTypeArguments = unboundParameterTypes + continuationType + context.builtIns.nullableAnyType functionClassTypeArguments = unboundParameterTypes + continuationType + context.builtIns.nullableAnyType
superTypes += functionClassDescriptor.defaultType.replace(functionClassTypeArguments) superTypes += functionClassDescriptor.defaultType.replace(functionClassTypeArguments)
superClasses += context.ir.symbols.functions[numberOfParameters + 1].owner
} }
coroutineClassDescriptor = ClassDescriptorImpl( coroutineClassDescriptor = ClassDescriptorImpl(
@@ -336,6 +339,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
origin = DECLARATION_ORIGIN_COROUTINE_IMPL, origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
descriptor = coroutineClassDescriptor descriptor = coroutineClassDescriptor
) )
coroutineClass.parent = irFunction.parent
val overriddenMap = mutableMapOf<CallableMemberDescriptor, CallableMemberDescriptor>() val overriddenMap = mutableMapOf<CallableMemberDescriptor, CallableMemberDescriptor>()
@@ -375,40 +379,35 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
doResumeFunctionSymbol = doResumeMethodBuilder.symbol) doResumeFunctionSymbol = doResumeMethodBuilder.symbol)
} }
val inheritedFromCoroutineImpl = coroutineImplClassDescriptor.unsubstitutedMemberScope val memberScope = stub<MemberScope>("coroutine class")
.getContributedDescriptors() coroutineClassDescriptor.initialize(memberScope, constructors, null)
.map { overriddenMap[it] ?: it.createFakeOverrideDescriptor(coroutineClassDescriptor) }
val contributedDescriptors = (
inheritedFromCoroutineImpl + invokeMethodBuilder?.symbol?.descriptor
).filterNotNull().toList()
coroutineClassDescriptor.initialize(SimpleMemberScope(contributedDescriptors), constructors, null)
coroutineClass.createParameterDeclarations() coroutineClass.createParameterDeclarations()
coroutineClassThis = coroutineClass.thisReceiver!!.symbol coroutineClassThis = coroutineClass.thisReceiver!!.symbol
coroutineClass.addFakeOverrides()
coroutineConstructorBuilder.initialize() coroutineConstructorBuilder.initialize()
coroutineClass.declarations.add(coroutineConstructorBuilder.ir) coroutineClass.addChild(coroutineConstructorBuilder.ir)
coroutineFactoryConstructorBuilder?.let { coroutineFactoryConstructorBuilder?.let {
it.initialize() it.initialize()
coroutineClass.declarations.add(it.ir) coroutineClass.addChild(it.ir)
} }
createMethodBuilder?.let { createMethodBuilder?.let {
it.initialize() it.initialize()
coroutineClass.declarations.add(it.ir) coroutineClass.addChild(it.ir)
} }
invokeMethodBuilder?.let { invokeMethodBuilder?.let {
it.initialize() it.initialize()
coroutineClass.declarations.add(it.ir) coroutineClass.addChild(it.ir)
} }
doResumeMethodBuilder.initialize() doResumeMethodBuilder.initialize()
coroutineClass.declarations.add(doResumeMethodBuilder.ir) coroutineClass.addChild(doResumeMethodBuilder.ir)
coroutineClass.setSuperSymbolsAndAddFakeOverrides(superClasses)
return BuiltCoroutine( return BuiltCoroutine(
coroutineClass = coroutineClass, coroutineClass = coroutineClass,
@@ -569,6 +568,8 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
createParameterDeclarations() createParameterDeclarations()
val thisReceiver = this.dispatchReceiverParameter!!.symbol
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody(startOffset, endOffset) { body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn( +irReturn(
@@ -579,7 +580,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
if (unboundArgsSet.contains(it)) if (unboundArgsSet.contains(it))
irGet(valueParameters[unboundIndex++].symbol) irGet(valueParameters[unboundIndex++].symbol)
else else
irGetField(irGet(coroutineClassThis), argumentToPropertiesMap[it]!!) irGetField(irGet(thisReceiver), argumentToPropertiesMap[it]!!)
}.forEachIndexed { index, argument -> }.forEachIndexed { index, argument ->
putValueArgument(index, argument) putValueArgument(index, argument)
} }
@@ -640,12 +641,14 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
createParameterDeclarations() createParameterDeclarations()
val thisReceiver = this.dispatchReceiverParameter!!.symbol
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody(startOffset, endOffset) { body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn( +irReturn(
irCall(doResumeFunctionSymbol).apply { irCall(doResumeFunctionSymbol).apply {
dispatchReceiver = irCall(createFunctionSymbol).apply { dispatchReceiver = irCall(createFunctionSymbol).apply {
dispatchReceiver = irGet(coroutineClassThis) dispatchReceiver = irGet(thisReceiver)
valueParameters.forEachIndexed { index, parameter -> valueParameters.forEachIndexed { index, parameter ->
putValueArgument(index, irGet(parameter.symbol)) putValueArgument(index, irGet(parameter.symbol))
} }
@@ -673,7 +676,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
initialize() initialize()
} }
coroutineClass.declarations.add(propertyBuilder.ir) coroutineClass.addChild(propertyBuilder.ir)
return propertyBuilder.symbol return propertyBuilder.symbol
} }
@@ -709,7 +712,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
outType = context.builtIns.nullableAnyType, outType = context.builtIns.nullableAnyType,
isMutable = true) isMutable = true)
) )
val label = coroutineClassDescriptor.unsubstitutedMemberScope val label = coroutineImplClassDescriptor.unsubstitutedMemberScope
.getContributedVariables(Name.identifier("label"), NoLookupLocation.FROM_BACKEND).single() .getContributedVariables(Name.identifier("label"), NoLookupLocation.FROM_BACKEND).single()
val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset)
@@ -747,6 +750,8 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
originalBody.transformChildrenVoid(object : IrElementTransformerVoid() { originalBody.transformChildrenVoid(object : IrElementTransformerVoid() {
private val thisReceiver = function.dispatchReceiverParameter!!.symbol
// Replace returns to refer to the new function. // Replace returns to refer to the new function.
override fun visitReturn(expression: IrReturn): IrExpression { override fun visitReturn(expression: IrReturn): IrExpression {
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
@@ -763,7 +768,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
val capturedValue = argumentToPropertiesMap[expression.descriptor] val capturedValue = argumentToPropertiesMap[expression.descriptor]
?: return expression ?: return expression
return irGetField(irGet(coroutineClassThis), capturedValue) return irGetField(irGet(thisReceiver), capturedValue)
} }
// Save/restore state at suspension points. // Save/restore state at suspension points.
@@ -782,10 +787,10 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
val scope = liveLocals[suspensionPoint]!! val scope = liveLocals[suspensionPoint]!!
return irBlock(expression) { return irBlock(expression) {
scope.forEach { scope.forEach {
+irSetField(irGet(coroutineClassThis), localToPropertyMap[it]!!, irGet(localsMap[it.descriptor] ?: it)) +irSetField(irGet(thisReceiver), localToPropertyMap[it]!!, irGet(localsMap[it.descriptor] ?: it))
} }
+irCall(coroutineImplLabelSetterSymbol).apply { +irCall(coroutineImplLabelSetterSymbol).apply {
dispatchReceiver = irGet(coroutineClassThis) dispatchReceiver = irGet(thisReceiver)
putValueArgument(0, irGet(suspensionPoint.suspensionPointIdParameter.symbol)) putValueArgument(0, irGet(suspensionPoint.suspensionPointIdParameter.symbol))
} }
} }
@@ -794,7 +799,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
val scope = liveLocals[suspensionPoint]!! val scope = liveLocals[suspensionPoint]!!
return irBlock(expression) { return irBlock(expression) {
scope.forEach { scope.forEach {
+irSetVar(localsMap[it.descriptor] ?: it, irGetField(irGet(coroutineClassThis), localToPropertyMap[it]!!)) +irSetVar(localsMap[it.descriptor] ?: it, irGetField(irGet(thisReceiver), localToPropertyMap[it]!!))
} }
} }
} }
@@ -813,7 +818,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
endOffset = endOffset, endOffset = endOffset,
type = context.builtIns.unitType, type = context.builtIns.unitType,
suspensionPointId = irCall(coroutineImplLabelGetterSymbol).apply { suspensionPointId = irCall(coroutineImplLabelGetterSymbol).apply {
dispatchReceiver = irGet(coroutineClassThis) dispatchReceiver = irGet(function.dispatchReceiverParameter!!.symbol)
}, },
result = irBlock(startOffset, endOffset) { result = irBlock(startOffset, endOffset) {
+irThrowIfNotNull(exceptionArgument) // Coroutine might start with an exception. +irThrowIfNotNull(exceptionArgument) // Coroutine might start with an exception.
@@ -46,10 +46,7 @@ import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.util.addFakeOverrides import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.addTopLevelInitializer
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
@@ -499,6 +496,7 @@ internal class TestProcessor (val context: KonanBackendContext) {
addMember(instanceGetterBuilder.ir) addMember(instanceGetterBuilder.ir)
companionGetterBuilder?.let { addMember(it.ir) } companionGetterBuilder?.let { addMember(it.ir) }
addFakeOverrides() addFakeOverrides()
setSuperSymbols(context.ir.symbols.symbolTable)
} }
override fun doInitialize() { override fun doInitialize() {
@@ -546,7 +544,7 @@ internal class TestProcessor (val context: KonanBackendContext) {
irFile.packageFragmentDescriptor, irFile.packageFragmentDescriptor,
testClass.functions)) { testClass.functions)) {
initialize() initialize()
irFile.declarations.add(ir) irFile.addChild(ir)
irFile.addTopLevelInitializer( irFile.addTopLevelInitializer(
IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, ir.symbol.constructors.single()) IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, ir.symbol.constructors.single())
) )
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.backend.konan.objcexport
import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters
import org.jetbrains.kotlin.backend.common.descriptors.isSuspend import org.jetbrains.kotlin.backend.common.descriptors.isSuspend
import org.jetbrains.kotlin.backend.konan.KONAN_FUNCTION_INTERFACES_MAX_PARAMETERS
import org.jetbrains.kotlin.backend.konan.ValueType import org.jetbrains.kotlin.backend.konan.ValueType
import org.jetbrains.kotlin.backend.konan.correspondingValueType import org.jetbrains.kotlin.backend.konan.correspondingValueType
import org.jetbrains.kotlin.backend.konan.descriptors.isArray import org.jetbrains.kotlin.backend.konan.descriptors.isArray
@@ -33,7 +34,7 @@ import org.jetbrains.kotlin.types.typeUtil.isUnit
internal interface ObjCExportMapper { internal interface ObjCExportMapper {
fun getCategoryMembersFor(descriptor: ClassDescriptor): List<CallableMemberDescriptor> fun getCategoryMembersFor(descriptor: ClassDescriptor): List<CallableMemberDescriptor>
val maxFunctionTypeParameterCount get() = 22 val maxFunctionTypeParameterCount get() = KONAN_FUNCTION_INTERFACES_MAX_PARAMETERS
fun isSpecialMapped(descriptor: ClassDescriptor): Boolean fun isSpecialMapped(descriptor: ClassDescriptor): Boolean
} }
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.backend.konan.DirectedGraph
import org.jetbrains.kotlin.backend.konan.DirectedGraphNode import org.jetbrains.kotlin.backend.konan.DirectedGraphNode
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
import org.jetbrains.kotlin.backend.konan.llvm.findMainEntryPoint
import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind
internal class CallGraphNode(val graph: CallGraph, val symbol: DataFlowIR.FunctionSymbol) internal class CallGraphNode(val graph: CallGraph, val symbol: DataFlowIR.FunctionSymbol)
@@ -94,7 +93,7 @@ internal class CallGraphBuilder(val context: Context,
fun build(): CallGraph { fun build(): CallGraph {
val rootSet = if (hasMain) { val rootSet = if (hasMain) {
listOf(symbolTable.mapFunction(findMainEntryPoint(context)!!).resolved()) + listOf(symbolTable.mapFunction(context.ir.symbols.entryPoint!!.owner).resolved()) +
moduleDFG.functions moduleDFG.functions
.map { it.key } .map { it.key }
.filter { it.isGlobalInitializer } .filter { it.isGlobalInitializer }
@@ -16,69 +16,60 @@
package org.jetbrains.kotlin.backend.konan.optimizations package org.jetbrains.kotlin.backend.konan.optimizations
import org.jetbrains.kotlin.backend.common.descriptors.allParameters import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.backend.common.descriptors.isSuspend
import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole
import org.jetbrains.kotlin.backend.common.peek import org.jetbrains.kotlin.backend.common.peek
import org.jetbrains.kotlin.backend.common.pop import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.allOverriddenDescriptors
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.backend.konan.descriptors.target import org.jetbrains.kotlin.backend.konan.descriptors.target
import org.jetbrains.kotlin.backend.konan.ir.IrSuspendableExpression import org.jetbrains.kotlin.backend.konan.ir.IrSuspendableExpression
import org.jetbrains.kotlin.backend.konan.ir.IrSuspensionPoint import org.jetbrains.kotlin.backend.konan.ir.IrSuspensionPoint
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.llvm.functionName import org.jetbrains.kotlin.backend.konan.llvm.functionName
import org.jetbrains.kotlin.backend.konan.llvm.localHash import org.jetbrains.kotlin.backend.konan.llvm.localHash
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.createValueSymbol
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.util.getArguments import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.util.simpleFunctions
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isNothing import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.util.OperatorNameConventions
private fun computeErasure(type: KotlinType, erasure: MutableList<ClassDescriptor>) { private fun computeErasure(type: KotlinType, context: Context, erasure: MutableList<ClassDescriptor>) {
val descriptor = type.constructor.declarationDescriptor val irClass = context.ir.getClass(type)
when (descriptor) { if (irClass != null) {
is ClassDescriptor -> erasure += descriptor erasure += irClass
is TypeParameterDescriptor -> { } else {
val descriptor = type.constructor.declarationDescriptor
if (descriptor is TypeParameterDescriptor) {
descriptor.upperBounds.forEach { descriptor.upperBounds.forEach {
computeErasure(it, erasure) computeErasure(it, context, erasure)
} }
} else {
TODO(descriptor.toString())
} }
else -> TODO(descriptor.toString())
} }
} }
internal fun KotlinType.erasure(): List<ClassDescriptor> { internal fun KotlinType.erasure(context: Context): List<ClassDescriptor> {
val result = mutableListOf<ClassDescriptor>() val result = mutableListOf<ClassDescriptor>()
computeErasure(this, result) computeErasure(this, context, result)
return result return result
} }
private fun MemberScope.getOverridingOf(function: FunctionDescriptor) = when (function) { private fun IrClass.getOverridingOf(function: FunctionDescriptor) = (function as? SimpleFunctionDescriptor)?.let {
is PropertyGetterDescriptor -> it.allOverriddenDescriptors.atMostOne { it.parent == this }
this.getContributedVariables(function.correspondingProperty.name, NoLookupLocation.FROM_BACKEND)
.firstOrNull { OverridingUtil.overrides(it, function.correspondingProperty) }?.getter
is PropertySetterDescriptor ->
this.getContributedVariables(function.correspondingProperty.name, NoLookupLocation.FROM_BACKEND)
.firstOrNull { OverridingUtil.overrides(it, function.correspondingProperty) }?.setter
else -> this.getContributedFunctions(function.name, NoLookupLocation.FROM_BACKEND)
.firstOrNull { OverridingUtil.overrides(it, function) }
} }
private fun IrTypeOperator.isCast() = private fun IrTypeOperator.isCast() =
@@ -122,7 +113,7 @@ private class VariableValues {
if (element !is IrGetValue) if (element !is IrGetValue)
result += element result += element
else { else {
val descriptor = element.descriptor val descriptor = element.symbol.owner
if (descriptor is VariableDescriptor && !seen.contains(descriptor)) if (descriptor is VariableDescriptor && !seen.contains(descriptor))
dfs(descriptor, seen, result) dfs(descriptor, seen, result)
} }
@@ -130,7 +121,8 @@ private class VariableValues {
} }
} }
private class ExpressionValuesExtractor(val returnableBlockValues: Map<IrReturnableBlock, List<IrExpression>>, private class ExpressionValuesExtractor(val context: Context,
val returnableBlockValues: Map<IrReturnableBlock, List<IrExpression>>,
val suspendableExpressionValues: Map<IrSuspendableExpression, List<IrSuspensionPoint>>) { val suspendableExpressionValues: Map<IrSuspendableExpression, List<IrSuspensionPoint>>) {
fun forEachValue(expression: IrExpression, block: (IrExpression) -> Unit) { fun forEachValue(expression: IrExpression, block: (IrExpression) -> Unit) {
@@ -187,11 +179,14 @@ private class ExpressionValuesExtractor(val returnableBlockValues: Map<IrReturna
is IrSetField -> block(expression) is IrSetField -> block(expression)
else -> { else -> {
if ((expression.type.isUnit() || expression.type.isNothing())) { val classSymbol = when {
block(IrGetObjectValueImpl(expression.startOffset, expression.endOffset, expression.type.isUnit() -> context.ir.symbols.unit
expression.type, IrClassSymbolImpl(expression.type.constructor.declarationDescriptor as ClassDescriptor))) expression.type.isNothing() -> context.ir.symbols.nothing
else -> TODO(ir2stringWhole(expression))
} }
else TODO(ir2stringWhole(expression))
block(IrGetObjectValueImpl(expression.startOffset, expression.endOffset,
expression.type, classSymbol))
} }
} }
} }
@@ -221,7 +216,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
// All suspension points within specified suspendable expression. // All suspension points within specified suspendable expression.
private val suspendableExpressionValues = mutableMapOf<IrSuspendableExpression, MutableList<IrSuspensionPoint>>() private val suspendableExpressionValues = mutableMapOf<IrSuspendableExpression, MutableList<IrSuspensionPoint>>()
private val expressionValuesExtractor = ExpressionValuesExtractor(returnableBlockValues, suspendableExpressionValues) private val expressionValuesExtractor = ExpressionValuesExtractor(context, returnableBlockValues, suspendableExpressionValues)
fun build(): ModuleDFG { fun build(): ModuleDFG {
val functions = mutableMapOf<DataFlowIR.FunctionSymbol, DataFlowIR.Function>() val functions = mutableMapOf<DataFlowIR.FunctionSymbol, DataFlowIR.Function>()
@@ -237,7 +232,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
println("Analysing function ${declaration.descriptor}") println("Analysing function ${declaration.descriptor}")
println("IR: ${ir2stringWhole(declaration)}") println("IR: ${ir2stringWhole(declaration)}")
} }
analyze(declaration.descriptor, it) analyze(declaration, it)
} }
} }
@@ -247,11 +242,11 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
println("Analysing global field ${declaration.descriptor}") println("Analysing global field ${declaration.descriptor}")
println("IR: ${ir2stringWhole(declaration)}") println("IR: ${ir2stringWhole(declaration)}")
} }
analyze(declaration.descriptor, IrSetFieldImpl(it.startOffset, it.endOffset, declaration.symbol, null, it.expression)) analyze(declaration, IrSetFieldImpl(it.startOffset, it.endOffset, declaration.symbol, null, it.expression))
} }
} }
private fun analyze(descriptor: CallableDescriptor, body: IrElement) { private fun analyze(descriptor: DeclarationDescriptor, body: IrElement) {
// Find all interesting expressions, variables and functions. // Find all interesting expressions, variables and functions.
val visitor = ElementFinderVisitor() val visitor = ElementFinderVisitor()
body.acceptVoid(visitor) body.acceptVoid(visitor)
@@ -346,14 +341,13 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
if (expression is IrCall && expression.symbol == scheduleImplSymbol) { if (expression is IrCall && expression.symbol == scheduleImplSymbol) {
// Producer of scheduleImpl is called externally, we need to reflect this somehow. // Producer of scheduleImpl is called externally, we need to reflect this somehow.
@Suppress("DEPRECATION") val producerInvocation = IrCallImpl(expression.startOffset, expression.endOffset,
val producerInvocation = IrCallImpl(expression.startOffset, expression.endOffset, scheduleImplProducerInvokeDescriptor) scheduleImplProducerInvoke.symbol, scheduleImplProducerInvoke.descriptor)
producerInvocation.dispatchReceiver = expression.getValueArgument(2) producerInvocation.dispatchReceiver = expression.getValueArgument(2)
expressions += producerInvocation expressions += producerInvocation
} }
if (expression is IrReturnableBlock) { if (expression is IrReturnableBlock) {
returnableBlocks.put(expression.descriptor, expression)
returnableBlockValues.put(expression, mutableListOf()) returnableBlockValues.put(expression, mutableListOf())
} }
if (expression is IrSuspendableExpression) { if (expression is IrSuspendableExpression) {
@@ -363,8 +357,6 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
if (expression is IrSuspensionPoint) if (expression is IrSuspensionPoint)
suspendableExpressionValues[suspendableExpressionStack.peek()!!]!!.add(expression) suspendableExpressionValues[suspendableExpressionStack.peek()!!]!!.add(expression)
super.visitExpression(expression) super.visitExpression(expression)
if (expression is IrReturnableBlock)
returnableBlocks.remove(expression.descriptor)
if (expression is IrSuspendableExpression) if (expression is IrSuspendableExpression)
suspendableExpressionStack.pop() suspendableExpressionStack.pop()
} }
@@ -375,7 +367,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
} }
override fun visitReturn(expression: IrReturn) { override fun visitReturn(expression: IrReturn) {
val returnableBlock = returnableBlocks[expression.returnTarget] val returnableBlock = expression.returnTargetSymbol.owner as? IrReturnableBlock
if (returnableBlock != null) { if (returnableBlock != null) {
returnableBlockValues[returnableBlock]!!.add(expression.value) returnableBlockValues[returnableBlock]!!.add(expression.value)
} else { // Non-local return. } else { // Non-local return.
@@ -391,39 +383,43 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
} }
override fun visitCatch(aCatch: IrCatch) { override fun visitCatch(aCatch: IrCatch) {
catchParameters.add(aCatch.parameter) catchParameters.add(aCatch.catchParameter)
super.visitCatch(aCatch) super.visitCatch(aCatch)
} }
override fun visitSetVariable(expression: IrSetVariable) { override fun visitSetVariable(expression: IrSetVariable) {
super.visitSetVariable(expression) super.visitSetVariable(expression)
assignVariable(expression.descriptor, expression.value) assignVariable(expression.symbol.owner, expression.value)
} }
override fun visitVariable(declaration: IrVariable) { override fun visitVariable(declaration: IrVariable) {
variableValues.addEmpty(declaration.descriptor) variableValues.addEmpty(declaration)
super.visitVariable(declaration) super.visitVariable(declaration)
declaration.initializer?.let { assignVariable(declaration.descriptor, it) } declaration.initializer?.let { assignVariable(declaration, it) }
} }
} }
private val doResumeFunctionDescriptor = context.getInternalClass("CoroutineImpl").unsubstitutedMemberScope private val doResumeFunctionSymbol =
.getContributedFunctions(Name.identifier("doResume"), NoLookupLocation.FROM_BACKEND).single() context.ir.symbols.coroutineImpl.owner.declarations
.filterIsInstance<IrSimpleFunction>().single { it.name.asString() == "doResume" }.symbol
private val getContinuationSymbol = context.ir.symbols.getContinuation private val getContinuationSymbol = context.ir.symbols.getContinuation
private val continuationType = getContinuationSymbol.descriptor.returnType!! private val continuationType = getContinuationSymbol.descriptor.returnType!!
private val arrayGetSymbol = context.ir.symbols.arrayGet private val arrayGetSymbol = context.ir.symbols.arrayGet
private val arraySetSymbol = context.ir.symbols.arraySet private val arraySetSymbol = context.ir.symbols.arraySet
private val scheduleImplSymbol = context.ir.symbols.scheduleImpl private val scheduleImplSymbol = context.ir.symbols.scheduleImpl
private val scheduleImplProducerClassSymbol = context.ir.symbols.functions[0]
private val scheduleImplProducerParam = scheduleImplSymbol.descriptor.valueParameters[2].also { private val scheduleImplProducerParam = scheduleImplSymbol.descriptor.valueParameters[2].also {
assert(it.name.asString() == "producer") assert(it.name.asString() == "producer")
assert(it.type.constructor.declarationDescriptor == scheduleImplProducerClassSymbol.descriptor)
} }
private val scheduleImplProducerInvokeDescriptor = scheduleImplProducerParam.type.memberScope private val scheduleImplProducerInvoke = scheduleImplProducerClassSymbol.owner.simpleFunctions()
.getContributedFunctions(Name.identifier("invoke"), NoLookupLocation.FROM_BACKEND).single() .single { it.name == OperatorNameConventions.INVOKE }
private inner class FunctionDFGBuilder(val expressionValuesExtractor: ExpressionValuesExtractor, private inner class FunctionDFGBuilder(val expressionValuesExtractor: ExpressionValuesExtractor,
val variableValues: VariableValues, val variableValues: VariableValues,
val descriptor: CallableDescriptor, val descriptor: DeclarationDescriptor,
val expressions: List<IrExpression>, val expressions: List<IrExpression>,
val returnValues: List<IrExpression>, val returnValues: List<IrExpression>,
val thrownValues: List<IrExpression>, val thrownValues: List<IrExpression>,
@@ -432,14 +428,15 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
private val allParameters = (descriptor as? FunctionDescriptor)?.allParameters ?: emptyList() private val allParameters = (descriptor as? FunctionDescriptor)?.allParameters ?: emptyList()
private val templateParameters = allParameters.withIndex().associateBy({ it.value }, { DataFlowIR.Node.Parameter(it.index) }) private val templateParameters = allParameters.withIndex().associateBy({ it.value }, { DataFlowIR.Node.Parameter(it.index) })
private val continuationParameter = private val continuationParameter = if (descriptor !is IrSimpleFunction) {
if (descriptor.isSuspend) null
DataFlowIR.Node.Parameter(allParameters.size) } else if (descriptor.isSuspend) {
else { DataFlowIR.Node.Parameter(allParameters.size)
if (doResumeFunctionDescriptor in descriptor.overriddenDescriptors) // <this> is a CoroutineImpl inheritor. } else if (doResumeFunctionSymbol in descriptor.overriddenSymbols) { // <this> is a CoroutineImpl inheritor.
templateParameters[descriptor.dispatchReceiverParameter!!] // It is its own continuation. templateParameters[descriptor.dispatchReceiverParameter!!] // It is its own continuation.
else null } else {
} null
}
private fun getContinuation() = continuationParameter ?: error("Function $descriptor has no continuation parameter") private fun getContinuation() = continuationParameter ?: error("Function $descriptor has no continuation parameter")
@@ -457,19 +454,28 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
private fun choosePrimary(erasure: List<ClassDescriptor>): ClassDescriptor { private fun choosePrimary(erasure: List<ClassDescriptor>): ClassDescriptor {
if (erasure.size == 1) return erasure[0] if (erasure.size == 1) return erasure[0]
// A parameter with constraints - choose class if exists. // A parameter with constraints - choose class if exists.
return erasure.singleOrNull { !it.isInterface } ?: context.builtIns.any return erasure.singleOrNull { !it.isInterface } ?: context.ir.symbols.any.owner
} }
fun build(): DataFlowIR.Function { fun build(): DataFlowIR.Function {
val isSuspend = descriptor is IrSimpleFunction && descriptor.isSuspend
expressions.forEach { getNode(it) } expressions.forEach { getNode(it) }
val returnNodeType = when (descriptor) {
is IrField -> descriptor.type
is IrFunction -> descriptor.returnType
else -> error(descriptor)
}
val returnsNode = DataFlowIR.Node.Variable( val returnsNode = DataFlowIR.Node.Variable(
values = returnValues.map { expressionToEdge(it) }, values = returnValues.map { expressionToEdge(it) },
type = symbolTable.mapType(descriptor.returnType ?: context.builtIns.unitType), type = symbolTable.mapType(returnNodeType),
kind = DataFlowIR.VariableKind.Temporary kind = DataFlowIR.VariableKind.Temporary
) )
val throwsNode = DataFlowIR.Node.Variable( val throwsNode = DataFlowIR.Node.Variable(
values = thrownValues.map { expressionToEdge(it) }, values = thrownValues.map { expressionToEdge(it) },
type = symbolTable.mapClass(context.builtIns.throwable), type = symbolTable.mapClass(context.ir.symbols.throwable.owner),
kind = DataFlowIR.VariableKind.Temporary kind = DataFlowIR.VariableKind.Temporary
) )
variables.forEach { descriptor, node -> variables.forEach { descriptor, node ->
@@ -478,12 +484,12 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
} }
} }
val allNodes = nodes.values + variables.values + templateParameters.values + returnsNode + throwsNode + val allNodes = nodes.values + variables.values + templateParameters.values + returnsNode + throwsNode +
(if (descriptor.isSuspend) listOf(continuationParameter!!) else emptyList()) (if (isSuspend) listOf(continuationParameter!!) else emptyList())
val parameterTypes = (allParameters.map { it.type } + (if (descriptor.isSuspend) listOf(continuationType) else emptyList())) val parameterTypes = (allParameters.map { it.type } + (if (isSuspend) listOf(continuationType) else emptyList()))
.map { symbolTable.mapClass(choosePrimary(it.erasure())) } .map { symbolTable.mapClass(choosePrimary(it.erasure(context))) }
.toTypedArray() .toTypedArray()
val returnType = if (descriptor.isSuspend) context.builtIns.anyType else (descriptor.returnType ?: context.builtIns.unitType) val returnType = if (isSuspend) context.builtIns.anyType else returnNodeType
return DataFlowIR.Function( return DataFlowIR.Function(
symbol = symbolTable.mapFunction(descriptor), symbol = symbolTable.mapFunction(descriptor),
parameterTypes = parameterTypes, parameterTypes = parameterTypes,
@@ -499,10 +505,10 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
private fun getNode(expression: IrExpression): DataFlowIR.Node { private fun getNode(expression: IrExpression): DataFlowIR.Node {
if (expression is IrGetValue) { if (expression is IrGetValue) {
val descriptor = expression.descriptor val descriptor = expression.symbol.owner
if (descriptor is ParameterDescriptor) if (descriptor is IrValueParameter)
return templateParameters[descriptor]!! return templateParameters[descriptor]!!
return variables[descriptor as VariableDescriptor]!! return variables[descriptor]!!
} }
return nodes.getOrPut(expression) { return nodes.getOrPut(expression) {
DEBUG_OUTPUT(0) { DEBUG_OUTPUT(0) {
@@ -541,7 +547,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
symbolTable.mapType(value.type), symbolTable.mapType(value.type),
if (value.type.isNothing()) // <Nothing> is not a singleton though its instance is get with <IrGetObject> operation. if (value.type.isNothing()) // <Nothing> is not a singleton though its instance is get with <IrGetObject> operation.
null null
else symbolTable.mapFunction(value.descriptor.constructors.single()) else symbolTable.mapFunction(value.symbol.owner.constructors.single())
) )
is IrCall -> when (value.symbol) { is IrCall -> when (value.symbol) {
@@ -554,7 +560,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
expressionToEdge(value.getValueArgument(0)!!), expressionToEdge(value.getValueArgument(1)!!)) expressionToEdge(value.getValueArgument(0)!!), expressionToEdge(value.getValueArgument(1)!!))
else -> { else -> {
val callee = value.descriptor val callee = value.symbol.owner as IrFunction
val arguments = value.getArguments() val arguments = value.getArguments()
.map { expressionToEdge(it.second) } .map { expressionToEdge(it.second) }
.let { .let {
@@ -580,11 +586,11 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
symbolTable.mapClass(owner), symbolTable.mapClass(owner),
callee.functionName.localHash.value, callee.functionName.localHash.value,
arguments, arguments,
symbolTable.mapType(callee.returnType!!), symbolTable.mapType(callee.returnType),
value value
) )
} else { } else {
val vtableIndex = vTableBuilder.vtableIndex(callee) val vtableIndex = vTableBuilder.vtableIndex(callee as IrSimpleFunction)
assert(vtableIndex >= 0, { "Unable to find function $callee in vtable of $owner" }) assert(vtableIndex >= 0, { "Unable to find function $callee in vtable of $owner" })
DataFlowIR.Node.VtableCall( DataFlowIR.Node.VtableCall(
symbolTable.mapFunction(callee.target), symbolTable.mapFunction(callee.target),
@@ -596,7 +602,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
) )
} }
} else { } else {
val actualCallee = (value.superQualifier?.unsubstitutedMemberScope?.getOverridingOf(callee) ?: callee).target val actualCallee = (value.superQualifierSymbol?.owner?.getOverridingOf(callee) ?: callee).target
DataFlowIR.Node.StaticCall( DataFlowIR.Node.StaticCall(
symbolTable.mapFunction(actualCallee), symbolTable.mapFunction(actualCallee),
arguments, arguments,
@@ -611,12 +617,12 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
is IrDelegatingConstructorCall -> { is IrDelegatingConstructorCall -> {
val thiz = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, val thiz = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
createValueSymbol((descriptor as ConstructorDescriptor).constructedClass.thisAsReceiverParameter)) (descriptor as ConstructorDescriptor).constructedClass.thisReceiver!!.symbol)
val arguments = listOf(thiz) + value.getArguments().map { it.second } val arguments = listOf(thiz) + value.getArguments().map { it.second }
DataFlowIR.Node.StaticCall( DataFlowIR.Node.StaticCall(
symbolTable.mapFunction(value.descriptor), symbolTable.mapFunction(value.symbol.owner),
arguments.map { expressionToEdge(it) }, arguments.map { expressionToEdge(it) },
symbolTable.mapClass(context.builtIns.unit), symbolTable.mapClass(context.ir.symbols.unit.owner),
symbolTable.mapType(thiz.type), symbolTable.mapType(thiz.type),
value value
) )
@@ -20,20 +20,19 @@ import org.jetbrains.kotlin.backend.common.descriptors.allParameters
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.isObjCClass import org.jetbrains.kotlin.backend.konan.isObjCClass
import org.jetbrains.kotlin.backend.konan.isValueType import org.jetbrains.kotlin.backend.konan.isValueType
import org.jetbrains.kotlin.backend.konan.llvm.functionName import org.jetbrains.kotlin.backend.konan.llvm.functionName
import org.jetbrains.kotlin.backend.konan.llvm.isExported import org.jetbrains.kotlin.backend.konan.llvm.isExported
import org.jetbrains.kotlin.backend.konan.llvm.localHash import org.jetbrains.kotlin.backend.konan.llvm.localHash
import org.jetbrains.kotlin.backend.konan.llvm.symbolName import org.jetbrains.kotlin.backend.konan.llvm.symbolName
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.descriptors.IrBuiltinOperatorDescriptorBase
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
@@ -421,7 +420,7 @@ internal object DataFlowIR {
private inline fun takeName(block: () -> String) = if (TAKE_NAMES) block() else null private inline fun takeName(block: () -> String) = if (TAKE_NAMES) block() else null
val classMap = mutableMapOf<ClassDescriptor, Type>() val classMap = mutableMapOf<ClassDescriptor, Type>()
val functionMap = mutableMapOf<CallableDescriptor, FunctionSymbol>() val functionMap = mutableMapOf<DeclarationDescriptor, FunctionSymbol>()
private val NAME_ESCAPES = Name.identifier("Escapes") private val NAME_ESCAPES = Name.identifier("Escapes")
private val NAME_POINTS_TO = Name.identifier("PointsTo") private val NAME_POINTS_TO = Name.identifier("PointsTo")
@@ -432,10 +431,10 @@ internal object DataFlowIR {
private val konanPackage = context.builtIns.builtInsModule.getPackage(FQ_NAME_KONAN).memberScope private val konanPackage = context.builtIns.builtInsModule.getPackage(FQ_NAME_KONAN).memberScope
private val escapesAnnotationDescriptor = konanPackage.getContributedClassifier( private val escapesAnnotationDescriptor = konanPackage.getContributedClassifier(
NAME_ESCAPES, NoLookupLocation.FROM_BACKEND) as ClassDescriptor NAME_ESCAPES, NoLookupLocation.FROM_BACKEND) as org.jetbrains.kotlin.descriptors.ClassDescriptor
private val escapesWhoDescriptor = escapesAnnotationDescriptor.unsubstitutedPrimaryConstructor!!.valueParameters.single() private val escapesWhoDescriptor = escapesAnnotationDescriptor.unsubstitutedPrimaryConstructor!!.valueParameters.single()
private val pointsToAnnotationDescriptor = konanPackage.getContributedClassifier( private val pointsToAnnotationDescriptor = konanPackage.getContributedClassifier(
NAME_POINTS_TO, NoLookupLocation.FROM_BACKEND) as ClassDescriptor NAME_POINTS_TO, NoLookupLocation.FROM_BACKEND) as org.jetbrains.kotlin.descriptors.ClassDescriptor
private val pointsToOnWhomDescriptor = pointsToAnnotationDescriptor.unsubstitutedPrimaryConstructor!!.valueParameters.single() private val pointsToOnWhomDescriptor = pointsToAnnotationDescriptor.unsubstitutedPrimaryConstructor!!.valueParameters.single()
var privateTypeIndex = 0 var privateTypeIndex = 0
@@ -448,17 +447,17 @@ internal object DataFlowIR {
} }
override fun visitFunction(declaration: IrFunction) { override fun visitFunction(declaration: IrFunction) {
declaration.body?.let { mapFunction(declaration.descriptor) } declaration.body?.let { mapFunction(declaration) }
} }
override fun visitField(declaration: IrField) { override fun visitField(declaration: IrField) {
declaration.initializer?.let { mapFunction(declaration.descriptor) } declaration.initializer?.let { mapFunction(declaration) }
} }
override fun visitClass(declaration: IrClass) { override fun visitClass(declaration: IrClass) {
declaration.acceptChildrenVoid(this) declaration.acceptChildrenVoid(this)
mapClass(declaration.descriptor) mapClass(declaration)
} }
}, data = null) }, data = null)
} }
@@ -501,40 +500,27 @@ internal object DataFlowIR {
return type return type
} }
fun mapType(type: KotlinType) = mapClass(type.erasure().single()) fun mapType(type: KotlinType) = mapClass(type.erasure(context).single())
// TODO: use from LlvmDeclarations. // TODO: use from LlvmDeclarations.
private fun getFqName(descriptor: DeclarationDescriptor): FqName { private fun getFqName(descriptor: DeclarationDescriptor): FqName =
if (descriptor is PackageFragmentDescriptor) { descriptor.parent.fqNameSafe.child(descriptor.name)
return descriptor.fqName
}
val containingDeclaration = descriptor.containingDeclaration
val parent = if (containingDeclaration != null) {
getFqName(containingDeclaration)
} else {
FqName.ROOT
}
val localName = descriptor.name
return parent.child(localName)
}
private val FunctionDescriptor.internalName get() = getFqName(this).asString() + "#internal" private val FunctionDescriptor.internalName get() = getFqName(this).asString() + "#internal"
fun mapFunction(descriptor: CallableDescriptor) = descriptor.original.let { fun mapFunction(descriptor: DeclarationDescriptor) = descriptor.original.let {
functionMap.getOrPut(it) { functionMap.getOrPut(it) {
when (it) { when (it) {
is PropertyDescriptor -> { is IrField -> {
// A global property initializer. // A global property initializer.
assert (it.dispatchReceiverParameter == null) { "All local properties initializers should've been lowered" } assert (it.parent !is IrClass) { "All local properties initializers should've been lowered" }
FunctionSymbol.Private(privateFunIndex++, 0, module, -1, true, takeName { "${it.symbolName}_init" }) FunctionSymbol.Private(privateFunIndex++, 0, module, -1, true, takeName { "${it.symbolName}_init" })
} }
is FunctionDescriptor -> { is FunctionDescriptor -> {
val name = if (it.isExported()) it.symbolName else it.internalName val name = if (it.isExported()) it.symbolName else it.internalName
val numberOfParameters = it.allParameters.size + if (it.isSuspend) 1 else 0 val numberOfParameters = it.allParameters.size + if (it.isSuspend) 1 else 0
if (it.module != irModule.descriptor || it.isExternal || (it is IrBuiltinOperatorDescriptorBase)) { if (it.module != irModule.descriptor || it.isExternal || (it.origin == IrDeclarationOrigin.IR_BUILTINS_STUB)) {
val escapesAnnotation = it.annotations.findAnnotation(FQ_NAME_ESCAPES) val escapesAnnotation = it.annotations.findAnnotation(FQ_NAME_ESCAPES)
val pointsToAnnotation = it.annotations.findAnnotation(FQ_NAME_POINTS_TO) val pointsToAnnotation = it.annotations.findAnnotation(FQ_NAME_POINTS_TO)
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@@ -544,7 +530,7 @@ internal object DataFlowIR {
FunctionSymbol.External(name.localHash.value, numberOfParameters, false, escapesBitMask, FunctionSymbol.External(name.localHash.value, numberOfParameters, false, escapesBitMask,
pointsToBitMask?.let { it.map { it.value }.toIntArray() }, takeName { name }) pointsToBitMask?.let { it.map { it.value }.toIntArray() }, takeName { name })
} else { } else {
val isAbstract = it.modality == Modality.ABSTRACT val isAbstract = it is SimpleFunctionDescriptor && it.modality == Modality.ABSTRACT
val classDescriptor = it.containingDeclaration as? ClassDescriptor val classDescriptor = it.containingDeclaration as? ClassDescriptor
val placeToFunctionsTable = !isAbstract && it !is ConstructorDescriptor && classDescriptor != null val placeToFunctionsTable = !isAbstract && it !is ConstructorDescriptor && classDescriptor != null
&& classDescriptor.kind != ClassKind.ANNOTATION_CLASS && classDescriptor.kind != ClassKind.ANNOTATION_CLASS
@@ -66,7 +66,7 @@ internal object Devirtualization {
return this return this
} }
val entryPoint = findMainEntryPoint(context) val entryPoint = context.ir.symbols.entryPoint?.owner
val exportedFunctions = val exportedFunctions =
if (entryPoint != null) if (entryPoint != null)
listOf(moduleDFG.symbolTable.mapFunction(entryPoint).resolved()) listOf(moduleDFG.symbolTable.mapFunction(entryPoint).resolved())
@@ -97,7 +97,7 @@ internal object Devirtualization {
val moduleDFG: ModuleDFG, val moduleDFG: ModuleDFG,
val externalModulesDFG: ExternalModulesDFG) { val externalModulesDFG: ExternalModulesDFG) {
private val entryPoint = findMainEntryPoint(context) private val entryPoint = context.ir.symbols.entryPoint?.owner
private val symbolTable = moduleDFG.symbolTable private val symbolTable = moduleDFG.symbolTable
@@ -506,7 +506,7 @@ internal object Devirtualization {
} }
val result = mutableMapOf<DataFlowIR.Node.VirtualCall, Pair<DevirtualizedCallSite, DataFlowIR.FunctionSymbol>>() val result = mutableMapOf<DataFlowIR.Node.VirtualCall, Pair<DevirtualizedCallSite, DataFlowIR.FunctionSymbol>>()
val nothing = symbolTable.mapClass(context.builtIns.nothing) val nothing = symbolTable.mapClass(context.ir.symbols.nothing.owner)
functions.values functions.values
.asSequence() .asSequence()
.filter { constraintGraph.functions.containsKey(it.symbol) } .filter { constraintGraph.functions.containsKey(it.symbol) }
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.backend.konan.optimizations
import org.jetbrains.kotlin.backend.konan.DirectedGraphCondensationBuilder import org.jetbrains.kotlin.backend.konan.DirectedGraphCondensationBuilder
import org.jetbrains.kotlin.backend.konan.DirectedGraphMultiNode import org.jetbrains.kotlin.backend.konan.DirectedGraphMultiNode
import org.jetbrains.kotlin.backend.konan.llvm.Lifetime import org.jetbrains.kotlin.backend.konan.llvm.Lifetime
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
internal object EscapeAnalysis { internal object EscapeAnalysis {
@@ -605,7 +604,7 @@ internal object EscapeAnalysis {
reachable += parameters.size reachable += parameters.size
reachabilities.add(reachable.toIntArray()) reachabilities.add(reachable.toIntArray())
visited.forEach { node -> visited.forEach { node ->
if (node !is ParameterDescriptor) if (node !is DataFlowIR.Node.Parameter)
nodes[node]!!.addIncomingParameter(it.index) nodes[node]!!.addIncomingParameter(it.index)
} }
} }
@@ -16,27 +16,30 @@
package org.jetbrains.kotlin.backend.konan.serialization package org.jetbrains.kotlin.backend.konan.serialization
import kotlin.properties.Delegates import org.jetbrains.kotlin.backend.konan.descriptors.isExpectMember
import org.jetbrains.kotlin.backend.konan.getObjCMethodInfo
import org.jetbrains.kotlin.backend.konan.isValueType
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.ProtoBuf.QualifiedNameTable.QualifiedName
import org.jetbrains.kotlin.backend.konan.llvm.isExported
import org.jetbrains.kotlin.backend.konan.llvm.typeInfoSymbolName
import org.jetbrains.kotlin.backend.konan.llvm.symbolName
import org.jetbrains.kotlin.backend.konan.llvm.localHash import org.jetbrains.kotlin.backend.konan.llvm.localHash
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
internal fun DeclarationDescriptor.symbolName(): String = when (this) { internal fun DeclarationDescriptor.symbolName(): String = when (this) {
is FunctionDescriptor is FunctionDescriptor
-> this.symbolName -> this.uniqueName
is PropertyDescriptor is PropertyDescriptor
-> this.symbolName -> this.uniqueName
is ClassDescriptor is ClassDescriptor
-> this.typeInfoSymbolName -> this.uniqueName
else -> error("Unexpected exported descriptor: $this") else -> error("Unexpected exported descriptor: $this")
} }
@@ -91,3 +94,203 @@ val IrBuiltIns.irBuiltInDescriptors
.map(IrSimpleFunction::descriptor) .map(IrSimpleFunction::descriptor)
// The declarations below are copied from `BinaryInterface.kt` when it was based on descriptors.
// TODO: do not serialize descriptors of non-exported declarations.
/**
* Defines whether the declaration is exported, i.e. visible from other modules.
*
* Exported declarations must have predictable and stable ABI
* that doesn't depend on any internal transformations (e.g. IR lowering),
* and so should be computable from the descriptor itself without checking a backend state.
*/
internal tailrec fun DeclarationDescriptor.isExported(): Boolean {
assert(!this.isExpectMember) { this }
if (this.annotations.findAnnotation(symbolNameAnnotation) != null) {
// Treat any `@SymbolName` declaration as exported.
return true
}
if (this.annotations.findAnnotation(exportForCppRuntimeAnnotation) != null) {
// Treat any `@ExportForCppRuntime` declaration as exported.
return true
}
if (this.annotations.findAnnotation(cnameAnnotation) != null) {
// Treat `@CName` declaration as exported.
return true
}
if (this.annotations.hasAnnotation(exportForCompilerAnnotation)) {
return true
}
if (this.annotations.hasAnnotation(publishedApiAnnotation)){
return true
}
if (this.annotations.hasAnnotation(inlineExposedAnnotation)){
return true
}
if (DescriptorUtils.isAnonymousObject(this))
return false
if (this is ConstructorDescriptor && constructedClass.kind.isSingleton) {
// Currently code generator can access the constructor of the singleton,
// so ignore visibility of the constructor itself.
return constructedClass.isExported()
}
if (this is PropertyAccessorDescriptor) {
return this.correspondingProperty.isExported()
}
if (this is DeclarationDescriptorWithVisibility && !this.visibility.isPublicAPI) {
// If the declaration is explicitly marked as non-public,
// then it must not be accessible from other modules.
return false
}
if (this is DeclarationDescriptorNonRoot) {
// If the declaration is not root, then check its container too.
return containingDeclaration.isExported()
}
return true
}
private val symbolNameAnnotation = FqName("konan.SymbolName")
private val exportForCppRuntimeAnnotation = FqName("konan.internal.ExportForCppRuntime")
private val cnameAnnotation = FqName("konan.internal.CName")
private val exportForCompilerAnnotation = FqName("konan.internal.ExportForCompiler")
private val publishedApiAnnotation = FqName("kotlin.PublishedApi")
private val inlineExposedAnnotation = FqName("kotlin.internal.InlineExposed")
private fun acyclicTypeMangler(visited: MutableSet<TypeParameterDescriptor>, type: KotlinType): String {
val descriptor = TypeUtils.getTypeParameterDescriptorOrNull(type)
if (descriptor != null) {
val upperBounds = if (visited.contains(descriptor)) "" else {
visited.add(descriptor)
descriptor.upperBounds.map {
val bound = acyclicTypeMangler(visited, it)
if (bound == "kotlin.Any?") "" else "_$bound"
}.joinToString("")
}
return "#GENERIC" + upperBounds
}
var hashString = TypeUtils.getClassDescriptor(type)!!.fqNameSafe.asString()
if (!type.arguments.isEmpty()) {
hashString += "<${type.arguments.map {
if (it.isStarProjection()) {
"#STAR"
} else {
val variance = it.projectionKind.label
val projection = if (variance == "") "" else "${variance}_"
projection + acyclicTypeMangler(visited, it.type)
}
}.joinToString(",")}>"
}
if (type.isMarkedNullable) hashString += "?"
return hashString
}
private fun typeToHashString(type: KotlinType)
= acyclicTypeMangler(mutableSetOf<TypeParameterDescriptor>(), type)
private val FunctionDescriptor.signature: String
get() {
val extensionReceiverPart = this.extensionReceiverParameter?.let { "@${typeToHashString(it.type)}." } ?: ""
val argsPart = this.valueParameters.map {
typeToHashString(it.type)
}.joinToString(";")
// Distinguish value types and references - it's needed for calling virtual methods through bridges.
// Also is function has type arguments - frontend allows exactly matching overrides.
val signatureSuffix =
when {
this.typeParameters.isNotEmpty() -> "Generic"
returnType.let { it != null && it.isValueType() } -> "ValueType"
returnType.let { it != null && !KotlinBuiltIns.isUnitOrNullableUnit(it) } -> typeToHashString(returnType!!)
else -> ""
}
return "$extensionReceiverPart($argsPart)$signatureSuffix"
}
// TODO: rename to indicate that it has signature included
private val FunctionDescriptor.uniqueLocalName: String
get() {
with(this.original) { // basic support for generics
this.getObjCMethodInfo()?.let {
return buildString {
if (extensionReceiverParameter != null) {
append(TypeUtils.getClassDescriptor(extensionReceiverParameter!!.type)!!.name)
append(".")
}
append("objc:")
append(it.selector)
}
}
return "$name$signature"
}
}
private val FunctionDescriptor.uniqueName: String
get() {
if (!this.isExported()) {
throw AssertionError(this.toString())
}
this.annotations.findAnnotation(symbolNameAnnotation)?.let {
if (this.isExternal) {
return getStringValue(it)!!
} else {
// ignore; TODO: report compile error
}
}
this.annotations.findAnnotation(exportForCppRuntimeAnnotation)?.let {
val name = getStringValue(it) ?: this.name.asString()
return name // no wrapping currently required
}
val containingDeclarationPart = containingDeclaration.fqNameSafe.let {
if (it.isRoot) "" else "$it."
}
return "kfun:$containingDeclarationPart$uniqueLocalName"
}
private val PropertyDescriptor.uniqueName: String
get() {
val containingDeclarationPart = containingDeclaration.fqNameSafe.let {
if (it.isRoot) "" else "$it."
}
val extensionReceiverPart = this.extensionReceiverParameter?.let { "${it.type}." } ?: ""
return "kprop:$containingDeclarationPart$extensionReceiverPart$name"
}
private fun getStringValue(annotation: AnnotationDescriptor): String? {
annotation.allValueArguments.values.ifNotEmpty {
val stringValue = this.single() as StringValue
return stringValue.value
}
return null
}
private val ClassDescriptor.uniqueName: String
get() {
assert (this.isExported())
return "ktype:" + this.fqNameSafe.toString()
}
@@ -39,6 +39,8 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.impl.* import org.jetbrains.kotlin.ir.symbols.impl.*
import org.jetbrains.kotlin.ir.util.addFakeOverrides import org.jetbrains.kotlin.ir.util.addFakeOverrides
import org.jetbrains.kotlin.ir.util.createParameterDeclarations import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.setOverrides
import org.jetbrains.kotlin.ir.util.setSuperSymbols
import org.jetbrains.kotlin.serialization.KonanDescriptorSerializer import org.jetbrains.kotlin.serialization.KonanDescriptorSerializer
import org.jetbrains.kotlin.serialization.KonanIr import org.jetbrains.kotlin.serialization.KonanIr
import org.jetbrains.kotlin.serialization.KonanIr.IrConst.ValueCase.* import org.jetbrains.kotlin.serialization.KonanIr.IrConst.ValueCase.*
@@ -1209,6 +1211,7 @@ internal class IrDeserializer(val context: Context,
clazz.createParameterDeclarations() clazz.createParameterDeclarations()
clazz.addFakeOverrides() clazz.addFakeOverrides()
clazz.setSuperSymbols(context.ir.symbols.symbolTable)
return clazz return clazz
@@ -1222,6 +1225,7 @@ internal class IrDeserializer(val context: Context,
descriptor, body as IrBody) descriptor, body as IrBody)
function.createParameterDeclarations() function.createParameterDeclarations()
function.setOverrides(context.ir.symbols.symbolTable)
proto.defaultArgumentList.forEach { proto.defaultArgumentList.forEach {
val expr = deserializeExpression(it.value) val expr = deserializeExpression(it.value)
@@ -20,19 +20,12 @@ import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrAnonymousInitializer import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrBindableSymbol import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.ir.visitors.*
@Deprecated("") @Deprecated("")
@@ -93,7 +86,7 @@ private fun IrModuleFragment.mergeFrom(other: IrModuleFragment): Unit {
if (thisPackage == null) { if (thisPackage == null) {
this.externalPackageFragments.add(it) this.externalPackageFragments.add(it)
} else { } else {
thisPackage.declarations.addAll(it.declarations) thisPackage.addChildren(it.declarations)
} }
} }
} }
@@ -120,42 +113,47 @@ private class IrUnboundSymbolReplacer(
val descriptorToSymbol: Map<DeclarationDescriptor, IrSymbol> val descriptorToSymbol: Map<DeclarationDescriptor, IrSymbol>
) : IrElementTransformerVoid() { ) : IrElementTransformerVoid() {
private inline fun <D : DeclarationDescriptor, reified S : IrBindableSymbol<D, *>> S.replace( private val localDescriptorToSymbol = mutableMapOf<DeclarationDescriptor, MutableList<IrSymbol>>()
private inline fun <R> withLocal(symbol: IrSymbol?, block: () -> R): R {
if (symbol == null) return block()
val locals = localDescriptorToSymbol.getOrPut(symbol.descriptor) { mutableListOf() }
locals.add(symbol)
return try {
block()
} finally {
locals.removeAt(locals.lastIndex)
}
}
private inline fun <reified D : DeclarationDescriptor, reified S : IrSymbol> S.replace(
referenceSymbol: (SymbolTable, D) -> S): S? { referenceSymbol: (SymbolTable, D) -> S): S? {
if (this.isBound) { if (this.isBound) {
return null return null
} }
localDescriptorToSymbol[this.descriptor]?.lastOrNull()?.let {
return it as S
}
descriptorToSymbol[this.descriptor]?.let { descriptorToSymbol[this.descriptor]?.let {
return it as S return it as S
} }
return referenceSymbol(symbolTable, this.descriptor) return referenceSymbol(symbolTable, this.descriptor as D)
} }
private inline fun <D : DeclarationDescriptor, reified S : IrBindableSymbol<D, *>> S.replaceOrSame( private inline fun <reified D : DeclarationDescriptor, reified S : IrSymbol> S.replaceOrSame(
referenceSymbol: (SymbolTable, D) -> S): S = this.replace(referenceSymbol) ?: this referenceSymbol: (SymbolTable, D) -> S): S = this.replace(referenceSymbol) ?: this
private fun IrFunctionSymbol.replace(
referenceSymbol: (SymbolTable, FunctionDescriptor) -> IrFunctionSymbol): IrFunctionSymbol? {
if (this.isBound) {
return null
}
descriptorToSymbol[this.descriptor]?.let {
return it as IrFunctionSymbol
}
return referenceSymbol(symbolTable, this.descriptor)
}
private inline fun <reified S : IrSymbol> S.replaceLocal(): S? { private inline fun <reified S : IrSymbol> S.replaceLocal(): S? {
return if (this.isBound) { return if (this.isBound) {
null null
} else { } else {
descriptorToSymbol[this.descriptor] as S (localDescriptorToSymbol[this.descriptor]?.lastOrNull() ?: descriptorToSymbol[this.descriptor]) as S
} }
} }
@@ -198,17 +196,8 @@ private class IrUnboundSymbolReplacer(
} }
override fun visitClassReference(expression: IrClassReference): IrExpression { override fun visitClassReference(expression: IrClassReference): IrExpression {
val symbol = expression.symbol.let { val symbol = expression.symbol.replace(SymbolTable::referenceClassifier)
if (it.isBound) { ?: return super.visitClassReference(expression)
return super.visitClassReference(expression)
}
descriptorToSymbol[it.descriptor]?.let {
it as IrClassifierSymbol
}
symbolTable.referenceClassifier(it.descriptor)
}
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
return with(expression) { return with(expression) {
@@ -216,6 +205,18 @@ private class IrUnboundSymbolReplacer(
} }
} }
override fun visitClass(declaration: IrClass): IrStatement {
declaration.superClasses.forEachIndexed { index, symbol ->
val newSymbol = symbol.replace(SymbolTable::referenceClass)
if (newSymbol != null) {
declaration.superClasses[index] = newSymbol
}
}
withLocal(declaration.thisReceiver?.symbol) {
return super.visitClass(declaration)
}
}
override fun visitGetField(expression: IrGetField): IrExpression { override fun visitGetField(expression: IrGetField): IrExpression {
val symbol = expression.symbol.replaceOrSame(SymbolTable::referenceField) val symbol = expression.symbol.replaceOrSame(SymbolTable::referenceField)
@@ -358,7 +359,20 @@ private class IrUnboundSymbolReplacer(
override fun visitFunction(declaration: IrFunction): IrStatement { override fun visitFunction(declaration: IrFunction): IrStatement {
returnTargetStack.push(declaration.symbol) returnTargetStack.push(declaration.symbol)
try { try {
return super.visitFunction(declaration) if (declaration is IrSimpleFunction) {
declaration.overriddenSymbols.forEachIndexed { index, symbol ->
val newSymbol = symbol.replace(SymbolTable::referenceSimpleFunction)
if (newSymbol != null) {
declaration.overriddenSymbols[index] = newSymbol
}
}
}
withLocal(declaration.dispatchReceiverParameter?.symbol) {
withLocal(declaration.extensionReceiverParameter?.symbol) {
return super.visitFunction(declaration)
}
}
} finally { } finally {
returnTargetStack.pop() returnTargetStack.pop()
} }
@@ -17,23 +17,25 @@
package org.jetbrains.kotlin.ir.util package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.expressions.IrConst import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.IrConstKind import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.resolve.OverridingStrategy
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import java.lang.reflect.Proxy
//TODO: delete file on next kotlin dependency update //TODO: delete file on next kotlin dependency update
internal fun IrExpression.isNullConst() = this is IrConst<*> && this.kind == IrConstKind.Null internal fun IrExpression.isNullConst() = this is IrConst<*> && this.kind == IrConstKind.Null
@@ -74,5 +76,272 @@ internal fun IrFile.addTopLevelInitializer(expression: IrExpression) {
irField.initializer = IrExpressionBodyImpl(expression.startOffset, expression.endOffset, initializer) irField.initializer = IrExpressionBodyImpl(expression.startOffset, expression.endOffset, initializer)
this.declarations.add(irField) this.addChild(irField)
}
fun IrClass.addFakeOverrides() {
val startOffset = this.startOffset
val endOffset = this.endOffset
descriptor.unsubstitutedMemberScope.getContributedDescriptors()
.filterIsInstance<CallableMemberDescriptor>()
.filter { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE }
.forEach {
this.addChild(createFakeOverride(it, startOffset, endOffset))
}
}
private fun createFakeOverride(descriptor: CallableMemberDescriptor, startOffset: Int, endOffset: Int): IrDeclaration {
fun FunctionDescriptor.createFunction(): IrFunction = IrFunctionImpl(
startOffset, endOffset,
IrDeclarationOrigin.FAKE_OVERRIDE, this
).apply {
createParameterDeclarations()
}
return when (descriptor) {
is FunctionDescriptor -> descriptor.createFunction()
is PropertyDescriptor ->
IrPropertyImpl(startOffset, endOffset, IrDeclarationOrigin.FAKE_OVERRIDE, descriptor).apply {
// TODO: add field if getter is missing?
getter = descriptor.getter?.createFunction()
setter = descriptor.setter?.createFunction()
}
else -> TODO(descriptor.toString())
}
}
fun IrFunction.createParameterDeclarations() {
fun ParameterDescriptor.irValueParameter() = IrValueParameterImpl(
innerStartOffset(this), innerEndOffset(this),
IrDeclarationOrigin.DEFINED,
this
).also {
it.parent = this@createParameterDeclarations
}
dispatchReceiverParameter = descriptor.dispatchReceiverParameter?.irValueParameter()
extensionReceiverParameter = descriptor.extensionReceiverParameter?.irValueParameter()
assert(valueParameters.isEmpty())
descriptor.valueParameters.mapTo(valueParameters) { it.irValueParameter() }
assert(typeParameters.isEmpty())
descriptor.typeParameters.mapTo(typeParameters) {
IrTypeParameterImpl(
innerStartOffset(it), innerEndOffset(it),
IrDeclarationOrigin.DEFINED,
it
).also { typeParameter ->
typeParameter.parent = this
}
}
}
fun IrSimpleFunction.setOverrides(symbolTable: SymbolTable) {
assert(this.overriddenSymbols.isEmpty())
this.descriptor.overriddenDescriptors.mapTo(this.overriddenSymbols) {
symbolTable.referenceSimpleFunction(it.original)
}
this.typeParameters.forEach { it.setSupers(symbolTable) }
}
fun IrClass.simpleFunctions(): List<IrSimpleFunction> = this.declarations.flatMap {
when (it) {
is IrSimpleFunction -> listOf(it)
is IrProperty -> listOfNotNull(it.getter as IrSimpleFunction?, it.setter as IrSimpleFunction?)
else -> emptyList()
}
}
fun IrClass.createParameterDeclarations() {
descriptor.thisAsReceiverParameter.let {
thisReceiver = IrValueParameterImpl(
innerStartOffset(it), innerEndOffset(it),
IrDeclarationOrigin.INSTANCE_RECEIVER,
it
).also { valueParameter ->
valueParameter.parent = this
}
}
assert(typeParameters.isEmpty())
descriptor.declaredTypeParameters.mapTo(typeParameters) {
IrTypeParameterImpl(
innerStartOffset(it), innerEndOffset(it),
IrDeclarationOrigin.DEFINED,
it
).also { typeParameter ->
typeParameter.parent = this
}
}
}
fun IrClass.setSuperSymbols(supers: List<IrClass>) {
assert(this.superDescriptors().toSet() == supers.map { it.descriptor }.toSet())
assert(this.superClasses.isEmpty())
supers.mapTo(this.superClasses) { it.symbol }
val superMembers = supers.flatMap {
it.simpleFunctions()
}.associateBy { it.descriptor }
this.simpleFunctions().forEach {
assert(it.overriddenSymbols.isEmpty())
it.descriptor.overriddenDescriptors.mapTo(it.overriddenSymbols) {
val superMember = superMembers[it.original] ?: error(it.original)
superMember.symbol
}
}
}
private fun IrClass.superDescriptors() =
this.descriptor.typeConstructor.supertypes.map { it.constructor.declarationDescriptor as ClassDescriptor }
fun IrClass.setSuperSymbols(symbolTable: SymbolTable) {
assert(this.superClasses.isEmpty())
this.superDescriptors().mapTo(this.superClasses) { symbolTable.referenceClass(it) }
this.simpleFunctions().forEach {
it.setOverrides(symbolTable)
}
this.typeParameters.forEach {
it.setSupers(symbolTable)
}
}
fun IrTypeParameter.setSupers(symbolTable: SymbolTable) {
assert(this.superClassifiers.isEmpty())
this.descriptor.upperBounds.mapNotNullTo(this.superClassifiers) {
it.constructor.declarationDescriptor?.let {
if (it is TypeParameterDescriptor) {
IrTypeParameterSymbolImpl(it) // Workaround for deserialized inline functions
} else {
symbolTable.referenceClassifier(it)
}
}
}
}
fun IrClass.setSuperSymbolsAndAddFakeOverrides(supers: List<IrClass>) {
val overriddenSuperMembers = this.declarations.map { it.descriptor }
.filterIsInstance<CallableMemberDescriptor>().flatMap { it.overriddenDescriptors.map { it.original } }
val unoverriddenSuperMembers = supers.flatMap {
it.declarations.mapNotNull {
when (it) {
is IrSimpleFunction -> it.descriptor
is IrProperty -> it.descriptor
else -> null
}
}
} - overriddenSuperMembers
val irClass = this
val overridingStrategy = object : OverridingStrategy() {
override fun addFakeOverride(fakeOverride: CallableMemberDescriptor) {
irClass.addChild(createFakeOverride(fakeOverride, startOffset, endOffset))
}
override fun inheritanceConflict(first: CallableMemberDescriptor, second: CallableMemberDescriptor) {
error("inheritance conflict in synthesized class ${irClass.descriptor}:\n $first\n $second")
}
override fun overrideConflict(fromSuper: CallableMemberDescriptor, fromCurrent: CallableMemberDescriptor) {
error("override conflict in synthesized class ${irClass.descriptor}:\n $fromSuper\n $fromCurrent")
}
}
unoverriddenSuperMembers.groupBy { it.name }.forEach { (name, members) ->
OverridingUtil.generateOverridesInFunctionGroup(
name,
members,
emptyList(),
this.descriptor,
overridingStrategy
)
}
this.setSuperSymbols(supers)
}
private fun IrElement.innerStartOffset(descriptor: DeclarationDescriptorWithSource): Int =
descriptor.startOffset ?: this.startOffset
private fun IrElement.innerEndOffset(descriptor: DeclarationDescriptorWithSource): Int =
descriptor.endOffset ?: this.endOffset
inline fun <reified T> stub(name: String): T {
return Proxy.newProxyInstance(T::class.java.classLoader, arrayOf(T::class.java)) { proxy, method, methodArgs ->
if (method.name == "toString" && method.parameterCount == 0) {
"${T::class.simpleName} stub for $name"
} else {
error("${T::class.simpleName}.${method.name} is not supported for $name")
}
} as T
}
fun IrDeclarationContainer.addChildren(declarations: List<IrDeclaration>) {
declarations.forEach { this.addChild(it) }
}
fun IrDeclarationContainer.addChild(declaration: IrDeclaration) {
this.declarations += declaration
declaration.accept(SetDeclarationsParentVisitor, this)
}
object SetDeclarationsParentVisitor : IrElementVisitor<Unit, IrDeclarationParent> {
override fun visitElement(element: IrElement, data: IrDeclarationParent) {
if (element !is IrDeclarationParent) {
element.acceptChildren(this, data)
}
}
override fun visitDeclaration(declaration: IrDeclaration, data: IrDeclarationParent) {
declaration.parent = data
super.visitDeclaration(declaration, data)
}
}
fun IrModuleFragment.checkDeclarationParents() {
this.accept(CheckDeclarationParentsVisitor, null)
this.dependencyModules.forEach { dependencyModule ->
dependencyModule.externalPackageFragments.forEach {
it.accept(CheckDeclarationParentsVisitor, null)
}
}
}
object CheckDeclarationParentsVisitor : IrElementVisitor<Unit, IrDeclarationParent?> {
override fun visitElement(element: IrElement, data: IrDeclarationParent?) {
element.acceptChildren(this, element as? IrDeclarationParent ?: data)
}
override fun visitDeclaration(declaration: IrDeclaration, data: IrDeclarationParent?) {
if (declaration !is IrVariable) {
checkParent(declaration, data)
} else {
// Don't check IrVariable parent.
}
super.visitDeclaration(declaration, data)
}
private fun checkParent(declaration: IrDeclaration, expectedParent: IrDeclarationParent?) {
val parent = try {
declaration.parent
} catch (e: Throwable) {
error("$declaration for ${declaration.descriptor} has no parent")
}
if (parent != expectedParent) {
error("$declaration for ${declaration.descriptor} has unexpected parent $parent")
}
}
} }
+7 -7
View File
@@ -20,16 +20,16 @@ remoteRoot=konan_tests
#kotlinCompilerModule=org.jetbrains.kotlin:kotlin-compiler:1.1-SNAPSHOT #kotlinCompilerModule=org.jetbrains.kotlin:kotlin-compiler:1.1-SNAPSHOT
# Download artifacts of https://teamcity.jetbrains.com/viewType.html?buildTypeId=Kotlin_120_Compiler # Download artifacts of https://teamcity.jetbrains.com/viewType.html?buildTypeId=Kotlin_120_Compiler
testDataVersion=1226829:id testDataVersion=1226829:id
kotlinCompilerRepo=https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:(id:Kotlin_dev_CompilerAllPlugins),number:1.2.40-dev-610/artifacts/content/maven kotlinCompilerRepo=https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:(id:Kotlin_dev_CompilerAllPlugins),number:1.2.40-dev-837/artifacts/content/maven
kotlinCompilerVersion=1.2.40-dev-610 kotlinCompilerVersion=1.2.40-dev-837
kotlinScriptRuntimeVersion=1.2.40-dev-610 kotlinScriptRuntimeVersion=1.2.40-dev-837
kotlinStdLibVersion=1.2.40-dev-610 kotlinStdLibVersion=1.2.40-dev-837
kotlinReflectVersion=1.2.40-dev-610 kotlinReflectVersion=1.2.40-dev-837
konanVersion=0.6.1 konanVersion=0.6.1
org.gradle.jvmargs='-Dfile.encoding=UTF-8' org.gradle.jvmargs='-Dfile.encoding=UTF-8'
## ##
# required for performance mesuarement tasks # required for performance mesuarement tasks
kotlinStdLibJdk8Version=1.2.40-dev-610 kotlinStdLibJdk8Version=1.2.40-dev-837
kotlinGradlePluginVersion=1.2.40-dev-610 kotlinGradlePluginVersion=1.2.40-dev-837