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 -> {
val function = declaration as FunctionDescriptor
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.
val bridge = if (!DescriptorUtils.isTopLevelDeclaration(function) && !function.isExtension &&
function.isOverridable) {
@@ -207,7 +207,7 @@ private class ExportedElement(val kind: ElementKind,
val receiver = param(0)
val numParams = LLVMCountParams(llvmFunction)
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)
ret(result)
}
@@ -223,14 +223,15 @@ private class ExportedElement(val kind: ElementKind,
val builder = LLVMCreateBuilder()!!
val bb = LLVMAppendBasicBlock(getTypeFunction, "")!!
LLVMPositionBuilderAtEnd(builder, bb)
LLVMBuildRet(builder, (declaration as ClassDescriptor).typeInfoPtr.llvm)
LLVMBuildRet(builder, context.ir.getFromCurrentModule(declaration as ClassDescriptor).typeInfoPtr.llvm)
LLVMDisposeBuilder(builder)
}
isEnumEntry -> {
// Produce entry getter.
cname = "_konan_function_${owner.nextFunctionIndex()}"
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)
}
}
@@ -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.LinkData
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.annotations.Annotations
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.declarations.*
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.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.endOffsetOrUndefined
import org.jetbrains.kotlin.ir.util.startOffsetOrUndefined
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.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
import java.lang.System.out
import kotlin.LazyThreadSafetyMode.PUBLICATION
@@ -56,7 +58,7 @@ import kotlin.LazyThreadSafetyMode.PUBLICATION
internal class SpecialDeclarationsFactory(val context: Context) {
private val enumSpecialDeclarationsFactory by lazy { EnumSpecialDeclarationsFactory(context) }
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>()
object DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS :
@@ -83,20 +85,31 @@ internal class SpecialDeclarationsFactory(val context: Context) {
)
}
fun getBridgeDescriptor(overriddenFunctionDescriptor: OverriddenFunctionDescriptor): FunctionDescriptor {
val descriptor = overriddenFunctionDescriptor.descriptor.original
fun getBridgeDescriptor(overriddenFunctionDescriptor: OverriddenFunctionDescriptor): IrSimpleFunction {
val irFunction = overriddenFunctionDescriptor.descriptor
val descriptor = irFunction.descriptor
assert(overriddenFunctionDescriptor.needBridge,
{ "Function $descriptor is not needed in a bridge to call overridden function ${overriddenFunctionDescriptor.overriddenDescriptor}" })
val bridgeDirections = overriddenFunctionDescriptor.bridgeDirections
return bridgesDescriptors.getOrPut(descriptor to bridgeDirections) {
SimpleFunctionDescriptorImpl.create(
return bridgesDescriptors.getOrPut(irFunction to bridgeDirections) {
val newDescriptor = SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ descriptor.containingDeclaration,
/* annotations = */ Annotations.EMPTY,
/* name = */ "<bridge-$bridgeDirections>${descriptor.functionName}".synthesizedName,
/* name = */ "<bridge-$bridgeDirections>${irFunction.functionName}".synthesizedName,
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE).apply {
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) {
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)
}
@@ -25,9 +25,8 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.ir.declarations.*
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.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
@@ -43,7 +42,7 @@ internal object DECLARATION_ORIGIN_ENUM :
internal data class LoweredEnum(val implObject: IrClass,
val valuesField: IrField,
val valuesGetter: IrSimpleFunction,
val itemGetterSymbol: IrFunctionSymbol,
val itemGetterSymbol: IrSimpleFunctionSymbol,
val itemGetterDescriptor: FunctionDescriptor,
val entriesMap: Map<Name, Int>)
@@ -74,7 +73,11 @@ internal class EnumSpecialDeclarationsFactory(val context: Context) {
val implObject = IrClassImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, implObjectDescriptor).apply {
createParameterDeclarations()
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)
@@ -114,10 +117,9 @@ internal class EnumSpecialDeclarationsFactory(val context: Context) {
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 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 typeParameterT = genericArrayType.declaredTypeParameters[0]
@@ -90,7 +90,7 @@ fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironme
phaser.phase(KonanPhase.BACKEND) {
phaser.phase(KonanPhase.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)
}
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.lower.*
import org.jetbrains.kotlin.backend.common.validateIrFile
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.DefaultArgumentStubGenerator
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.ir.declarations.IrFile
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
internal class KonanLower(val context: Context) {
fun lower() {
val irModule = context.irModule!!
// Phases to run against whole module.
lowerModule(context.irModule!!)
lowerModule(irModule)
// Phases to run against a file.
context.irModule!!.files.forEach {
irModule.files.forEach {
lowerFile(it)
}
irModule.checkDeclarationParents()
}
private fun lowerModule(irModule: IrModuleFragment) {
@@ -73,8 +79,17 @@ internal class KonanLower(val context: Context) {
irModule.files.forEach(LateinitLowering(context)::lower)
}
@Suppress("DEPRECATION")
irModule.replaceUnboundSymbols(context)
val symbolTable = context.ir.symbols.symbolTable
irModule.referenceAllTypeExternalClassifiers(symbolTable)
do {
@Suppress("DEPRECATION")
irModule.replaceUnboundSymbols(context)
irModule.referenceAllTypeExternalClassifiers(symbolTable)
} while (symbolTable.unboundClasses.isNotEmpty())
irModule.patchDeclarationParents()
validateIrModule(context, irModule)
}
@@ -144,7 +159,7 @@ internal class KonanLower(val context: Context) {
WorkersBridgesBuilding(context).lower(irFile)
}
phaser.phase(KonanPhase.AUTOBOX) {
validateIrFile(context, irFile)
// validateIrFile(context, irFile) // Temporarily disabled until moving to new IR finished.
Autoboxing(context).lower(irFile)
}
phaser.phase(KonanPhase.RETURNS_INSERTION) {
@@ -80,3 +80,8 @@ object KonanPlatform : TargetPlatform("Konan") {
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
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.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
// We check that either method is open, or one of declarations it overrides is open.
get() = isOverridable || DescriptorUtils.getAllOverriddenDeclarations(this).any { it.isOverridable }
internal class OverriddenFunctionDescriptor(val descriptor: FunctionDescriptor, overriddenDescriptor: FunctionDescriptor) {
internal class OverriddenFunctionDescriptor(
val descriptor: SimpleFunctionDescriptor,
overriddenDescriptor: SimpleFunctionDescriptor
) {
val overriddenDescriptor = overriddenDescriptor.original
val needBridge: Boolean
@@ -44,16 +39,15 @@ internal class OverriddenFunctionDescriptor(val descriptor: FunctionDescriptor,
return descriptor.canObjCClassMethodBeCalledVirtually(this.overriddenDescriptor)
}
// We check that either method is open, or one of declarations it overrides is open.
return overriddenDescriptor.canBeCalledVirtually
return overriddenDescriptor.isOverridable
}
val inheritsBridge: Boolean
get() = !descriptor.kind.isReal
&& OverridingUtil.overrides(descriptor.target, overriddenDescriptor)
get() = !descriptor.isReal
&& descriptor.target.overrides(overriddenDescriptor)
&& descriptor.bridgeDirectionsTo(overriddenDescriptor).allNotNeeded()
fun getImplementation(context: Context): FunctionDescriptor {
fun getImplementation(context: Context): SimpleFunctionDescriptor {
val target = descriptor.target
if (!needBridge) return target
val bridgeOwner = if (inheritsBridge) {
@@ -90,17 +84,18 @@ internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val con
assert(!classDescriptor.isInterface)
val superVtableEntries = if (KotlinBuiltIns.isSpecialClassWithNoSupertypes(classDescriptor)) {
val superVtableEntries = if (classDescriptor.isSpecialClassWithNoSupertypes()) {
emptyList()
} else {
context.getVtableBuilder(classDescriptor.getSuperClassOrAny()).vtableEntries
val superClass = classDescriptor.getSuperClassNotAny() ?: context.ir.symbols.any.owner
context.getVtableBuilder(superClass).vtableEntries
}
val methods = classDescriptor.sortedContributedMethods
val newVtableSlots = mutableListOf<OverriddenFunctionDescriptor>()
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) {
superMethod
} else {
@@ -122,7 +117,7 @@ internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val con
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 index = vtableEntries.indexOfFirst { it.descriptor == function.original && it.bridgeDirections == bridgeDirections }
if (index < 0) throw Error(function.toString() + " not in vtable of " + classDescriptor.toString())
@@ -16,27 +16,18 @@
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.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.isValueType
import org.jetbrains.kotlin.backend.konan.llvm.functionName
import org.jetbrains.kotlin.backend.konan.llvm.localHash
import org.jetbrains.kotlin.backend.konan.llvm.isExported
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
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.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.simpleFunctions
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.typeUtil.isUnit
import org.jetbrains.kotlin.util.OperatorNameConventions
/**
* 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 }
return (superClassImplementedInterfaces +
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
*/
internal fun <T : CallableMemberDescriptor> T.resolveFakeOverride(): T {
if (this.kind.isReal) {
internal tailrec fun IrSimpleFunction.resolveFakeOverride(): IrSimpleFunction {
if (this.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
return overriddenSymbols
.firstOrNull { it.owner.modality != Modality.ABSTRACT }!!
.owner.resolveFakeOverride()
}
}
private val intrinsicAnnotation = FqName("konan.internal.Intrinsic")
internal val CallableDescriptor.isIntrinsic: Boolean
internal val FunctionDescriptor.isIntrinsic: Boolean
get() = this.annotations.hasAnnotation(intrinsicAnnotation)
private val intrinsicTypes = setOf(
@@ -81,7 +70,7 @@ private val intrinsicTypes = setOf(
"kotlin.Float", "kotlin.Double"
)
private val arrayTypes = setOf(
internal val arrayTypes = setOf(
"kotlin.Array",
"kotlin.ByteArray",
"kotlin.CharArray",
@@ -105,82 +94,20 @@ internal val ClassDescriptor.isArray: Boolean
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 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>
internal val IrClass.sortedContributedMethods: List<SimpleFunctionDescriptor>
get () = contributedMethods.sortedBy {
it.functionName.localHash.value
}
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
}
internal val IrClass.contributedMethods: List<SimpleFunctionDescriptor>
get () = this.simpleFunctions()
fun ClassDescriptor.isAbstract() = this.modality == Modality.SEALED || this.modality == Modality.ABSTRACT
|| this.kind == ClassKind.ENUM_CLASS
internal fun FunctionDescriptor.hasValueTypeAt(index: Int): Boolean {
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() }
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 {
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() }
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)
= (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
internal val FunctionDescriptor.target: FunctionDescriptor get() = when (this) {
is SimpleFunctionDescriptor -> this.target
is ConstructorDescriptor -> this
else -> error(this)
}
internal enum class BridgeDirection {
NOT_NEEDED,
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)
for (index in ourDirections.array.indices)
ourDirections.array[index] = this.bridgeDirectionToAt(overriddenDescriptor, index)
val target = this.target
if (!kind.isReal && modality != Modality.ABSTRACT
&& OverridingUtil.overrides(target, overriddenDescriptor)
if (!this.isReal && modality != Modality.ABSTRACT
&& target.overrides(overriddenDescriptor)
&& ourDirections == target.bridgeDirectionsTo(overriddenDescriptor)) {
// Bridge is inherited from superclass.
return BridgeDirections(this.valueParameters.size)
@@ -265,82 +215,10 @@ internal fun FunctionDescriptor.bridgeDirectionsTo(overriddenDescriptor: Functio
}
tailrec internal fun DeclarationDescriptor.findPackage(): PackageFragmentDescriptor {
return if (this is PackageFragmentDescriptor) this
else this.containingDeclaration!!.findPackage()
val parent = this.parent
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 =
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.Symbols
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.descriptors.getMemberScope
import org.jetbrains.kotlin.backend.konan.llvm.findMainEntryPoint
import org.jetbrains.kotlin.backend.konan.lower.TestProcessor
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.descriptors.*
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.IrEnumEntrySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType
import kotlin.properties.Delegates
@@ -51,10 +50,56 @@ internal class KonanIr(context: Context, irModule: IrModuleFragment): Ir<Context
lateinit var moduleIndexForCodegen: ModuleIndex
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) {
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 =
symbolTable.referenceSimpleFunction(context.interopBuiltIns.nativePointedGetRawPointer)
@@ -83,6 +128,15 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
val interopInterpretObjCPointerOrNull =
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 boxFunctions = ValueType.values().associate {
@@ -97,7 +151,7 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
val valueClassToBox = ValueType.values().associate {
val valueClassId = ClassId.topLevel(it.classFqName.toSafe())
val valueClassDescriptor = context.builtIns.builtInsModule.findClassAcrossModuleDependencies(valueClassId)!!
valueClassDescriptor to boxClasses[it]!!
symbolTable.referenceClass(valueClassDescriptor) to boxClasses[it]!!
}
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)
)
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 topLevelSuite = getKonanTestClass("TopLevelSuite")
val testFunctionKind = getKonanTestClass("TestFunctionKind")
@@ -267,8 +330,17 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
private val testFunctionKindCache = mutableMapOf<TestProcessor.FunctionKind, IrEnumEntrySymbol>()
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
) 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 enumEntries: Map<ClassDescriptor, IrEnumEntry>
/**
* Contains all functions declared in [module]
*/
@@ -41,6 +43,7 @@ class ModuleIndex(val module: IrModuleFragment) {
init {
val map = mutableMapOf<ClassDescriptor, IrClass>()
enumEntries = mutableMapOf()
module.acceptVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
@@ -58,6 +61,12 @@ class ModuleIndex(val module: IrModuleFragment) {
map[declaration.descriptor] = declaration
}
override fun visitEnumEntry(declaration: IrEnumEntry) {
super.visitEnumEntry(declaration)
enumEntries[declaration.descriptor] = declaration
}
override fun visitFunction(declaration: IrFunction) {
super.visitFunction(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
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.isExpectMember
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.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.isValueType
import org.jetbrains.kotlin.backend.konan.library.KonanLibraryReader
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.ir.declarations.*
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.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
// This file describes the ABI for Kotlin descriptors of exported declarations.
// TODO: revise the naming scheme to ensure it produces unique names.
// TODO: do not serialize descriptors of non-exported declarations.
@@ -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.
*/
internal tailrec fun DeclarationDescriptor.isExported(): Boolean {
assert(!this.isExpectMember) { this }
// TODO: revise
if (this.annotations.findAnnotation(symbolNameAnnotation) != null) {
// Treat any `@SymbolName` declaration as exported.
@@ -73,7 +71,7 @@ internal tailrec fun DeclarationDescriptor.isExported(): Boolean {
return true
}
if (DescriptorUtils.isAnonymousObject(this))
if (this.isAnonymousObject)
return false
if (this is ConstructorDescriptor && constructedClass.kind.isSingleton) {
@@ -82,19 +80,33 @@ internal tailrec fun DeclarationDescriptor.isExported(): Boolean {
return constructedClass.isExported()
}
if (this is PropertyAccessorDescriptor) {
return this.correspondingProperty.isExported()
if (this is IrFunction) {
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,
// 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()
val parent = this.parent
if (parent is IrDeclaration) {
return parent.isExported()
}
return true
@@ -158,8 +170,8 @@ private val FunctionDescriptor.signature: String
val signatureSuffix =
when {
this.typeParameters.isNotEmpty() -> "Generic"
returnType.let { it != null && it.isValueType() } -> "ValueType"
returnType.let { it != null && !KotlinBuiltIns.isUnitOrNullableUnit(it) } -> typeToHashString(returnType!!)
returnType.isValueType() -> "ValueType"
!KotlinBuiltIns.isUnitOrNullableUnit(returnType) -> typeToHashString(returnType)
else -> ""
}
return "$extensionReceiverPart($argsPart)$signatureSuffix"
@@ -188,7 +200,7 @@ internal val FunctionDescriptor.functionName: String
internal val FunctionDescriptor.symbolName: String
get() {
if (!this.isExported()) {
throw AssertionError(this.toString())
throw AssertionError(this.descriptor.toString())
}
this.annotations.findAnnotation(symbolNameAnnotation)?.let {
@@ -204,19 +216,20 @@ internal val FunctionDescriptor.symbolName: String
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."
}
return "kfun:$containingDeclarationPart$functionName"
}
internal val PropertyDescriptor.symbolName: String
internal val IrField.symbolName: String
get() {
val containingDeclarationPart = containingDeclaration.fqNameSafe.let {
val containingDeclarationPart = parent.fqNameSafe.let {
if (it.isRoot) "" else "$it."
}
val extensionReceiverPart = this.extensionReceiverParameter?.let { "${it.type}." } ?: ""
return "kprop:$containingDeclarationPart$extensionReceiverPart$name"
return "kprop:$containingDeclarationPart$name"
}
@@ -235,7 +248,7 @@ internal fun RuntimeAware.getLlvmFunctionType(function: FunctionDescriptor): LLV
val returnType = when {
original is ConstructorDescriptor -> voidType
original.isSuspend -> kObjHeaderPtr // Suspend functions return Any?.
else -> getLLVMReturnType(original.returnType!!)
else -> getLLVMReturnType(original.returnType)
}
val paramTypes = ArrayList(original.allParameters.map { getLLVMType(it.type) })
if (original.isSuspend)
@@ -21,14 +21,9 @@ import kotlinx.cinterop.*
import llvm.*
import org.jetbrains.kotlin.backend.konan.Context
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.isObjCClass
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
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
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
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 {
val descriptorForTypeInfo = if (constructedClass.isObjCClass()) {
context.interopBuiltIns.objCPointerHolder
context.ir.symbols.objCPointerHolder.owner
} else {
constructedClass
}
@@ -549,7 +544,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
assert (typeInfoPtr.type == codegen.kTypeInfoPtr) { LLVMPrintTypeToString(typeInfoPtr.type)!!.toKString() }
val llvmMethod = if (!owner.isInterface) {
// If this is a virtual method of the class - we can call via vtable.
val index = context.getVtableBuilder(owner).vtableIndex(descriptor)
val index = context.getVtableBuilder(owner).vtableIndex(descriptor as SimpleFunctionDescriptor)
val vtablePlace = gep(typeInfoPtr, Int32(1).llvm) // typeInfoPtr + 1
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].
*/
fun getEnumEntry(descriptor: ClassDescriptor, exceptionHandler: ExceptionHandler): LLVMValueRef {
assert(descriptor.kind == ClassKind.ENUM_ENTRY)
fun getEnumEntry(descriptor: IrEnumEntry, exceptionHandler: ExceptionHandler): LLVMValueRef {
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 values = call(
loweredEnum.valuesGetter.descriptor.original.llvmFunction,
loweredEnum.valuesGetter.llvmFunction,
emptyList(),
Lifetime.ARGUMENT,
exceptionHandler
)
return call(
loweredEnum.itemGetterDescriptor.original.llvmFunction,
loweredEnum.itemGetterSymbol.owner.llvmFunction,
listOf(values, Int32(ordinal).llvm),
Lifetime.GLOBAL,
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.DeserializedKonanModule
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.backend.konan.hash.GlobalHash
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.isNativeBinary
import org.jetbrains.kotlin.backend.konan.library.KonanLibraryReader
import org.jetbrains.kotlin.backend.konan.library.impl.LibraryReaderImpl
import org.jetbrains.kotlin.backend.konan.library.withResolvedDependencies
import org.jetbrains.kotlin.descriptors.ClassDescriptor
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.IrExternalPackageFragment
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.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.reflect.KProperty
@@ -162,7 +159,14 @@ internal interface ContextUtils : RuntimeAware {
val staticData: 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.
@@ -170,10 +174,7 @@ internal interface ContextUtils : RuntimeAware {
*/
val FunctionDescriptor.llvmFunction: LLVMValueRef
get() {
assert (this.kind.isReal)
if (this is TypeAliasConstructorDescriptor) {
return this.underlyingConstructorDescriptor.llvmFunction
}
assert (this.isReal)
return if (isExternal(this)) {
context.llvm.externalFunction(this.symbolName, getLlvmFunctionType(this),
@@ -209,12 +210,6 @@ internal interface ContextUtils : RuntimeAware {
val ClassDescriptor.llvmTypeInfoPtr: LLVMValueRef
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].
*
@@ -21,8 +21,8 @@ import kotlinx.cinterop.memScoped
import llvm.*
import org.jetbrains.kotlin.backend.konan.Context
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.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.SourceManager.FileEntry
import org.jetbrains.kotlin.ir.declarations.IrFile
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>
get() {
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)
@@ -52,7 +52,7 @@ internal fun findMainEntryPoint(context: Context): FunctionDescriptor? {
it.returnType?.isUnit() == true &&
it.hasSingleArrayOfStringParameter &&
it.typeParameters.isEmpty() &&
it.isExported()
it.visibility.isPublicAPI
}
if (main == null) {
context.reportCompilationError("Could not find '$entryName' in '$packageName' package.")
@@ -19,39 +19,37 @@ package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.*
import llvm.*
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.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.*
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.optimizations.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.SourceManager
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.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.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
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.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlin.types.typeUtil.isUnit
internal fun emitLLVM(context: Context) {
@@ -153,7 +151,7 @@ internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid {
override fun visitClass(declaration: IrClass) {
super.visitClass(declaration)
val descriptor = declaration.descriptor
val descriptor = declaration
if (descriptor.isIntrinsic) {
// do not generate any code for intrinsic classes as they require special handling
return
@@ -181,7 +179,7 @@ internal interface CodeContext {
*
* @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)
@@ -270,7 +268,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private object TopLevelCodeContext : CodeContext {
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()
@@ -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.compiler.used", context.llvm.compilerUsedGlobals)
appendStaticInitializers()
appendEntryPointSelector(findMainEntryPoint(context))
appendEntryPointSelector(context.ir.symbols.entryPoint?.owner)
if (context.isDynamicLibrary) {
appendCAdapters()
}
@@ -371,7 +369,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
appendingTo(bbDeinit) {
context.llvm.fileInitializers.forEach {
val descriptor = it.descriptor
val descriptor = it
if (descriptor.type.isValueType())
return@forEach // Is not a subject for memory management.
val address = context.llvmDeclarations.forStaticField(descriptor).storage
@@ -386,7 +384,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
.forEach {
if (it.initializer?.expression !is IrConst<*>?) {
val initialization = evaluateExpression(it.initializer!!.expression)
val address = context.llvmDeclarations.forStaticField(it.descriptor).storage
val address = context.llvmDeclarations.forStaticField(it).storage
storeAny(initialization, address)
}
}
@@ -479,7 +477,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
override fun visitConstructor(declaration: IrConstructor) {
context.log{"visitConstructor : ${ir2string(declaration)}"}
if (declaration.descriptor.containingDeclaration.isIntrinsic) {
if (declaration.constructedClass.isIntrinsic) {
// Do not generate any ctors for intrinsic classes.
return
}
@@ -489,18 +487,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
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)
}
@@ -543,19 +529,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
function: IrFunction?,
private val functionGenerationContext: FunctionGenerationContext): InnerScopeImpl() {
val parameters = bindParameters(function?.descriptor)
val parameters = bindParameters(function)
init {
if (function != null) {
parameters.forEach{
val descriptor = it.key
val ir = when {
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 ir = descriptor
val local = functionGenerationContext.vars.createParameter(descriptor,
debugInfoIfNeeded(function, ir))
@@ -587,15 +567,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
var llvmFunction:LLVMValueRef? = declaration?.let{
codegen.llvmFunction(declaration.descriptor)
codegen.llvmFunction(it)
}
private var name:String? = declaration?.descriptor?.name?.asString()
override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) {
if (declaration == null || target == declaration.descriptor) {
if (target.returnsUnit()) {
assert (value == null)
override fun genReturn(target: IrSymbolOwner, value: LLVMValueRef?) {
if (declaration == null || target == declaration) {
if ((target as IrFunction).returnsUnit()) {
functionGenerationContext.ret(null)
} else {
functionGenerationContext.ret(value!!)
@@ -654,7 +633,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (declaration.descriptor.isExternal) return
if (body == null) return
generateFunction(codegen, declaration.descriptor,
generateFunction(codegen, declaration,
declaration.location(declaration.startLine(), declaration.startColumn()),
declaration.location(declaration.endLine(), declaration.endColumn())) {
using(FunctionScope(declaration, it)) {
@@ -674,7 +653,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (declaration.descriptor.usedAnnotation) {
context.llvm.usedFunctions.add(codegen.llvmFunction(declaration.descriptor))
context.llvm.usedFunctions.add(codegen.llvmFunction(declaration))
}
if (context.shouldVerifyBitCode())
@@ -713,7 +692,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
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) {
context.log{"visitField : ${ir2string(declaration)}"}
debugFieldDeclaration(declaration)
val descriptor = declaration.descriptor
val descriptor = declaration
if (context.needGlobalInit(declaration)) {
val type = codegen.getLLVMType(descriptor.type)
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 =
functionGenerationContext.getObjectValue(
value.descriptor,
value.symbol.owner,
currentCodeContext.exceptionHandler,
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")
}
val arrayClass = context.ir.getClass(value.type)!!
// 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).
// 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) {
fun genCatchBlock() {
using(VariableScope()) {
currentCodeContext.genDeclareVariable(catch.parameter, exception, null)
currentCodeContext.genDeclareVariable(catch.catchParameter, exception, null)
evaluateExpressionAndJump(catch.result, success)
}
}
@@ -1008,7 +991,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
genCatchBlock()
return // Remaining catch clauses are unreachable.
} else {
val isInstance = genInstanceOf(exception, catch.parameter.type)
val isInstance = genInstanceOf(exception, catch.getCatchParameterTypeClass(context)!!)
val body = functionGenerationContext.basicBlock("catch", catch.startLocation)
val nextCheck = functionGenerationContext.basicBlock("catchCheck", catch.endLocation)
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 {
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 {
context.log{"evaluateSetVariable : ${ir2string(value)}"}
val result = evaluateExpression(value.value)
val variable = currentCodeContext.getDeclaredVariable(value.descriptor)
val variable = currentCodeContext.getDeclaredVariable(value.symbol.owner)
functionGenerationContext.vars.store(result, variable)
assert(value.type.isUnit())
return functionGenerationContext.theUnitInstanceRef.llvm
@@ -1177,7 +1167,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
functionScope = locationInfo.scope,
diType = element.descriptor.type.diType(context, codegen.llvmTargetData),
name = element.descriptor.name,
argNo = (element.descriptor as? ValueParameterDescriptor)?.index ?: 0,
argNo = if (element.isValueParameter) element.index else 0,
file = file,
line = locationInfo.line,
location = location)
@@ -1189,7 +1179,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
context.log{"generateVariable : ${ir2string(variable)}"}
val value = variable.initializer?.let { evaluateExpression(it) }
currentCodeContext.genDeclareVariable(
variable.descriptor, value, debugInfoIfNeeded(
variable, value, debugInfoIfNeeded(
(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 {
context.log{"evaluateCast : ${ir2string(value)}"}
val type = value.typeOperand
assert(!KotlinBuiltIns.isPrimitiveType(type) && !KotlinBuiltIns.isPrimitiveType(value.argument.type))
assert(!type.isTypeParameter())
val dstDescriptor = TypeUtils.getClassDescriptor(type) // Get class descriptor for dst type.
val dstTypeInfo = codegen.typeInfoValue(dstDescriptor!!) // Get TypeInfo for dst type.
val dstDescriptor = value.getTypeOperandClass(context)!!
assert(!KotlinBuiltIns.isPrimitiveType(dstDescriptor.defaultType) &&
!KotlinBuiltIns.isPrimitiveType(value.argument.type))
val dstTypeInfo = codegen.typeInfoValue(dstDescriptor) // Get TypeInfo for dst type.
val srcArg = evaluateExpression(value.argument) // Evaluate src expression.
val srcObjInfoPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, srcArg) // Cast src to ObjInfoPtr.
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.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)
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 {
val dstDescriptor = TypeUtils.getClassDescriptor(type) ?: return kTrue // Get class descriptor for dst type.
// Reified parameters are not yet supported.
// Workaround for reified parameters
val dstTypeInfo = codegen.typeInfoValue(dstDescriptor) // Get TypeInfo for dst type.
private fun genInstanceOf(obj: LLVMValueRef, dstClass: IrClass): LLVMValueRef {
val dstTypeInfo = codegen.typeInfoValue(dstClass) // Get TypeInfo for dst type.
val srcObjInfoPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, obj) // Cast src to ObjInfoPtr.
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) {
val thisPtr = evaluateExpression(value.receiver!!)
return functionGenerationContext.loadSlot(
fieldPtrOfClass(thisPtr, value.descriptor), value.descriptor.isVar())
fieldPtrOfClass(thisPtr, value.symbol.owner), value.descriptor.isVar())
}
else {
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())
}
}
@@ -1339,11 +1333,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (value.descriptor.dispatchReceiverParameter != null) {
val thisPtr = evaluateExpression(value.receiver!!)
functionGenerationContext.storeAny(valueToAssign, fieldPtrOfClass(thisPtr, value.descriptor))
functionGenerationContext.storeAny(valueToAssign, fieldPtrOfClass(thisPtr, value.symbol.owner))
}
else {
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)
}
@@ -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 classDescriptor = value.containingDeclaration as ClassDescriptor
@@ -1402,7 +1396,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
return if (classDescriptor.isObjCClass()) {
assert(classDescriptor.isKotlinObjCClass())
val objCPtr = callDirect(context.interopBuiltIns.objCPointerHolderValue.getter!!,
val objCPtr = callDirect(context.ir.symbols.objCPointerHolderValueGetter.owner,
listOf(objectPtr), Lifetime.IRRELEVANT)
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 target = expression.returnTarget
val ret = if (target.returnsUnit()) {
null
} else {
evaluated
}
val target = expression.returnTargetSymbol.owner
currentCodeContext.genReturn(target, ret)
currentCodeContext.genReturn(target, evaluated)
return codegen.kNothingFakeValue
}
@@ -1487,15 +1476,15 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
return resultPhi!!
}
override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) {
if (target != returnableBlock.descriptor) { // It is not our "local return".
override fun genReturn(target: IrSymbolOwner, value: LLVMValueRef?) {
if (target != returnableBlock) { // It is not our "local return".
super.genReturn(target, value)
return
}
// It is local return from current function.
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.
}
}
@@ -1538,7 +1527,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private inner class ClassScope(val clazz:IrClass) : InnerScopeImpl() {
val isExported
get() = clazz.descriptor.isExported()
get() = clazz.isExported()
var offsetInBits = 0L
val members = mutableListOf<DIDerivedTypeRef>()
@Suppress("UNCHECKED_CAST")
@@ -1547,7 +1536,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
tag = DwarfTag.DW_TAG_structure_type.value,
refBuilder = context.debugInfo.builder,
refScope = (currentCodeContext.fileScope() as FileScope).file.file() as DIScopeOpaqueRef,
name = clazz.descriptor.typeInfoSymbolName,
name = clazz.typeInfoSymbolName,
refFile = file().file(),
line = clazz.startLine()) as DITypeOpaqueRef
else null
@@ -1619,12 +1608,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun evaluateSpecialIntrinsicCall(expression: IrFunctionAccessExpression): LLVMValueRef? {
if (expression.descriptor.isIntrinsic) {
when (expression.descriptor.original) {
val function = expression.symbol.owner as IrFunction
if (function.isIntrinsic) {
when (function.descriptor) {
context.interopBuiltIns.objCObjectInitBy -> {
val receiver = evaluateExpression(expression.extensionReceiver!!)
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 args = listOf(receiver) + constructorArgs
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 initializer = callee.getValueArgument(1) as IrCall
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
}
}
@@ -1661,7 +1656,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
updateBuilderDebugLocation(value)
when {
value is IrDelegatingConstructorCall ->
return delegatingConstructorCall(value.descriptor, args)
return delegatingConstructorCall(value.symbol.owner, args)
else ->
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(
refBuilder = context.debugInfo.builder,
refScope = scope.scope as DIScopeOpaqueRef,
name = expression.descriptor.symbolName,
name = expression.symbolName,
file = irFile.file(),
lineNum = expression.startLine(),
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")
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 doResumeFunctionDescriptor = coroutineImplDescriptor.unsubstitutedMemberScope
.getContributedFunctions(Name.identifier("doResume"), NoLookupLocation.FROM_BACKEND).single()
private val coroutineImplDescriptor = context.ir.symbols.coroutineImpl.owner
private val doResumeFunctionDescriptor = coroutineImplDescriptor.declarations
.filterIsInstance<IrSimpleFunction>().single { it.name.asString() == "doResume" }
private fun getContinuation(): LLVMValueRef {
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.
else {
// 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'" })
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.
@@ -1824,7 +1819,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
assert (expression.getArguments().isEmpty())
val descriptor = expression.descriptor
val descriptor = expression.symbol.owner as IrFunction
assert (descriptor.dispatchReceiverParameter == null)
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 id = currentCodeContext.addResumePoint(bbResume)
using (SuspensionPointScope(expression.suspensionPointIdParameter.descriptor, bbResume, id)) {
using (SuspensionPointScope(expression.suspensionPointIdParameter, bbResume, id)) {
continuationBlock(expression.type, expression.result.startLocation).run {
val normalResult = evaluateExpression(expression.result)
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>,
resultLifetime: Lifetime): LLVMValueRef {
val descriptor = callee.descriptor
val descriptor = callee.symbol.owner as IrFunction
val argsWithContinuationIfNeeded = if (descriptor.isSuspend)
args + getContinuation()
@@ -1918,11 +1913,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (callee is IrPrivateFunctionCall)
return evaluatePrivateFunctionCall(callee, argsWithContinuationIfNeeded, resultLifetime)
when (descriptor) {
is IrBuiltinOperatorDescriptorBase -> return evaluateOperatorCall (callee, argsWithContinuationIfNeeded)
is ConstructorDescriptor -> return evaluateConstructorCall (callee, argsWithContinuationIfNeeded)
else -> return evaluateSimpleFunctionCall(
descriptor, argsWithContinuationIfNeeded, resultLifetime, callee.superQualifier)
when {
descriptor.origin == IrDeclarationOrigin.IR_BUILTINS_STUB ->
return evaluateOperatorCall(callee, argsWithContinuationIfNeeded)
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 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)
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>,
resultLifetime: Lifetime, superClass: ClassDescriptor? = null): LLVMValueRef {
//context.log{"evaluateSimpleFunctionCall : $tmpVariableName = ${ir2string(value)}"}
if (descriptor.isOverridable && superClass == null)
if (superClass == null && descriptor is SimpleFunctionDescriptor && descriptor.isOverridable)
return callVirtual(descriptor, args, resultLifetime)
else
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 {
context.log{"evaluateConstructorCall : ${ir2string(callee)}"}
return memScoped {
val constructedClass = (callee.descriptor as ConstructorDescriptor).constructedClass
val constructedClass = (callee.symbol as IrConstructorSymbol).owner.constructedClass
val thisValue = if (constructedClass.isArray) {
assert(args.isNotEmpty() && args[0].type == int32Type)
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,
lifetime = resultLifetime(callee))
} else if (constructedClass.isKotlinObjCClass()) {
callDirect(context.interopBuiltIns.allocObjCObject, listOf(genGetObjCClass(constructedClass)),
callDirect(context.ir.symbols.allocObjCObject.owner, listOf(genGetObjCClass(constructedClass)),
resultLifetime(callee))
} else {
functionGenerationContext.allocInstance(constructedClass, resultLifetime(callee))
}
evaluateSimpleFunctionCall(callee.descriptor,
evaluateSimpleFunctionCall(callee.symbol.owner as IrFunction,
listOf(thisValue) + args, Lifetime.IRRELEVANT /* constructor doesn't return anything */)
thisValue
}
@@ -2074,8 +2073,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
interop.getObjCClass -> {
val typeArgument = callee.getTypeArgument(descriptor.typeParameters.single())
val classDescriptor = TypeUtils.getClassDescriptor(typeArgument!!)!!
genGetObjCClass(classDescriptor)
val irClass = context.ir.getClass(typeArgument!!)!!
genGetObjCClass(irClass)
}
interop.getObjCMessenger -> {
@@ -2090,16 +2089,16 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
context.ir.symbols.getClassTypeInfo.descriptor -> {
val typeArgument = callee.getTypeArgumentOrDefault(descriptor.typeParameters.single())
val typeArgumentClass = TypeUtils.getClassDescriptor(typeArgument)
val typeArgumentClass = context.ir.getClass(typeArgument)
if (typeArgumentClass == null) {
// E.g. for `T::class` in a body of an inline function itself.
functionGenerationContext.unreachable()
kNullInt8Ptr
} else {
val classDescriptor = context.ir.symbols.valueClassToBox[typeArgumentClass]?.descriptor
val irClass = context.ir.symbols.valueClassToBox[typeArgumentClass.symbol]?.owner
?: typeArgumentClass
val typeInfo = codegen.typeInfoValue(classDescriptor)
val typeInfo = codegen.typeInfoValue(irClass)
LLVMConstBitCast(typeInfo, kInt8Ptr)!!
}
}
@@ -2107,8 +2106,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
context.ir.symbols.createUninitializedInstance.descriptor -> {
val typeParameterT = context.ir.symbols.createUninitializedInstance.descriptor.typeParameters[0]
val enumClass = callee.getTypeArgument(typeParameterT)!!
val enumClassDescriptor = enumClass.constructor.declarationDescriptor as ClassDescriptor
functionGenerationContext.allocInstance(enumClassDescriptor, resultLifetime(callee))
val enumIrClass = context.ir.getClass(enumClass)!!
functionGenerationContext.allocInstance(enumIrClass, resultLifetime(callee))
}
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 {
return callDirect(context.interopBuiltIns.objCPointerHolder.unsubstitutedPrimaryConstructor!!,
return callDirect(context.ir.symbols.objCPointerHolder.owner.constructors.single(),
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 {
context.log{"evaluateOperatorCall : origin:${ir2string(callee)}"}
val descriptor = callee.descriptor
val descriptor = callee.symbol.owner as IrFunction
val ib = context.irModule!!.irBuiltins
with(functionGenerationContext) {
return when {
descriptor == ib.eqeqeq -> icmpEq(args[0], args[1])
descriptor == ib.booleanNot -> icmpNe(args[0], kTrue)
descriptor == ib.eqeqeqFun -> icmpEq(args[0], args[1])
descriptor == ib.booleanNotFun -> icmpNe(args[0], kTrue)
descriptor.isComparisonDescriptor(ib.greaterFunByOperandType) -> {
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 {
val constructedClass = functionGenerationContext.constructedClass!!
val thisPtr = currentCodeContext.genGetValue(constructedClass.thisAsReceiverParameter)
val thisPtr = currentCodeContext.genGetValue(constructedClass.thisReceiver!!)
if (constructedClass.isObjCClass()) {
return codegen.theUnitInstanceRef.llvm
@@ -18,44 +18,40 @@ package org.jetbrains.kotlin.backend.konan.llvm
import llvm.LLVMStoreSizeOfType
import llvm.LLVMValueRef
import org.jetbrains.kotlin.backend.common.atMostOne
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.getStringValueOrNull
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.isFinalClass
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.ir.declarations.IrClass
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.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
internal class KotlinObjCClassInfoGenerator(override val context: Context) : ContextUtils {
fun generate(irClass: IrClass) {
val descriptor = irClass.descriptor
assert(descriptor.isFinalClass)
assert(irClass.isFinalClass)
val objCLLvmDeclarations = context.llvmDeclarations.forClass(descriptor).objCDeclarations!!
val objCLLvmDeclarations = context.llvmDeclarations.forClass(irClass).objCDeclarations!!
val instanceMethods = generateInstanceMethodDescs(irClass)
val companionObjectDescriptor = descriptor.companionObjectDescriptor
val classMethods = companionObjectDescriptor?.generateOverridingMethodDescs() ?: emptyList()
val companionObject = irClass.declarations.filterIsInstance<IrClass>().atMostOne { it.isCompanion }
val classMethods = companionObject?.generateOverridingMethodDescs() ?: emptyList()
val superclassName = descriptor.getSuperClassNotAny()!!.let {
val superclassName = irClass.getSuperClassNotAny()!!.let {
context.llvm.imports.add(it.llvmSymbolOrigin)
it.name.asString()
}
val protocolNames = descriptor.getSuperInterfaces().map {
val protocolNames = irClass.getSuperInterfaces().map {
context.llvm.imports.add(it.llvmSymbolOrigin)
it.name.asString().removeSuffix("Protocol")
}
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,
className,
@@ -73,8 +69,8 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
Int32(bodySize),
objCLLvmDeclarations.bodyOffsetGlobal.pointer,
descriptor.typeInfoPtr,
companionObjectDescriptor?.typeInfoPtr ?: NullPointer(runtime.typeInfoType),
irClass.typeInfoPtr,
companionObject?.typeInfoPtr ?: NullPointer(runtime.typeInfoType),
objCLLvmDeclarations.classPointerGlobal.pointer
)
@@ -88,13 +84,12 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
private fun generateInstanceMethodDescs(
irClass: IrClass
): List<ObjCMethodDesc> = mutableListOf<ObjCMethodDesc>().apply {
val descriptor = irClass.descriptor
addAll(descriptor.generateOverridingMethodDescs())
addAll(irClass.generateOverridingMethodDescs())
addAll(irClass.generateImpMethodDescs())
val allImplementedSelectors = this.map { it.selector }.toSet()
assert(descriptor.getSuperClassNotAny()!!.isExternalObjCClass())
val allInitMethodsInfo = descriptor.getSuperClassNotAny()!!.constructors
assert(irClass.getSuperClassNotAny()!!.isExternalObjCClass())
val allInitMethodsInfo = irClass.getSuperClassNotAny()!!.constructors
.mapNotNull { it.getObjCInitMethod()?.getExternalObjCMethodInfo() }
.filter { it.selector !in allImplementedSelectors }
.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 =
descriptor.annotations.findAnnotation(context.interopBuiltIns.exportObjCClass.fqNameSafe)
irClass.annotations.findAnnotation(context.interopBuiltIns.exportObjCClass.fqNameSafe)
return if (exportObjCClassAnnotation != null) {
exportObjCClassAnnotation.getStringValueOrNull("name") ?: descriptor.name.asString()
} else if (descriptor.isExported()) {
descriptor.fqNameSafe.asString()
exportObjCClassAnnotation.getStringValueOrNull("name") ?: irClass.name.asString()
} else if (irClass.isExported()) {
irClass.fqNameSafe.asString()
} else {
null // Generate as anonymous.
}
@@ -138,22 +133,21 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
)
)
private fun ClassDescriptor.generateOverridingMethodDescs(): List<ObjCMethodDesc> =
this.unsubstitutedMemberScope.contributedMethods.filter {
it.kind.isReal && it !is ConstructorDescriptor
}.mapNotNull { it.getObjCMethodInfo() }.map { generateMethodDesc(it) }
private fun IrClass.generateOverridingMethodDescs(): List<ObjCMethodDesc> =
this.simpleFunctions().filter { it.isReal }
.mapNotNull { it.getObjCMethodInfo() }.map { generateMethodDesc(it) }
private fun IrClass.generateImpMethodDescs(): List<ObjCMethodDesc> = this.declarations
.filterIsInstance<IrSimpleFunction>()
.mapNotNull {
val annotation =
it.descriptor.annotations.findAnnotation(context.interopBuiltIns.objCMethodImp.fqNameSafe) ?:
it.annotations.findAnnotation(context.interopBuiltIns.objCMethodImp.fqNameSafe) ?:
return@mapNotNull null
ObjCMethodDesc(
annotation.getStringValue("selector"),
annotation.getStringValue("encoding"),
it.descriptor.llvmFunction
it.llvmFunction
)
}
}
@@ -20,18 +20,13 @@ import kotlinx.cinterop.*
import llvm.*
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.MainFunctionDetector
import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
internal fun createLlvmDeclarations(context: Context): LlvmDeclarations {
val generator = DeclarationsGeneratorVisitor(context)
@@ -47,8 +42,8 @@ internal fun createLlvmDeclarations(context: Context): LlvmDeclarations {
internal class LlvmDeclarations(
private val functions: Map<FunctionDescriptor, FunctionLlvmDeclarations>,
private val classes: Map<ClassDescriptor, ClassLlvmDeclarations>,
private val fields: Map<PropertyDescriptor, FieldLlvmDeclarations>,
private val staticFields: Map<PropertyDescriptor, StaticFieldLlvmDeclarations>,
private val fields: Map<IrField, FieldLlvmDeclarations>,
private val staticFields: Map<IrField, StaticFieldLlvmDeclarations>,
private val theUnitInstanceRef: ConstPointer?
) {
fun forFunction(descriptor: FunctionDescriptor) = functions[descriptor] ?:
@@ -57,10 +52,10 @@ internal class LlvmDeclarations(
fun forClass(descriptor: ClassDescriptor) = classes[descriptor] ?:
error(descriptor.toString())
fun forField(descriptor: PropertyDescriptor) = fields[descriptor] ?:
fun forField(descriptor: IrField) = fields[descriptor] ?:
error(descriptor.toString())
fun forStaticField(descriptor: PropertyDescriptor) = staticFields[descriptor] ?:
fun forStaticField(descriptor: IrField) = staticFields[descriptor] ?:
error(descriptor.toString())
fun forSingleton(descriptor: ClassDescriptor) = forClass(descriptor).singletonDeclarations ?:
@@ -72,7 +67,7 @@ internal class LlvmDeclarations(
internal class ClassLlvmDeclarations(
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 writableTypeInfoGlobal: StaticData.Global?,
val typeInfo: ConstPointer,
@@ -101,7 +96,7 @@ internal class StaticFieldLlvmDeclarations(val storage: LLVMValueRef)
*/
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 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.
*/
private fun Context.getDeclaredFields(classDescriptor: ClassDescriptor): List<PropertyDescriptor> {
private fun Context.getDeclaredFields(classDescriptor: ClassDescriptor): List<IrField> {
// TODO: Here's what is going on here:
// The existence of a backing field for a property is only described in the IR,
// but not in the PropertyDescriptor.
@@ -122,33 +117,24 @@ private fun Context.getDeclaredFields(classDescriptor: ClassDescriptor): List<Pr
// In this function we check the presence of the backing field
// two ways: first we check IR, then we check the protobuf extension.
val irClass = ir.moduleIndexForCodegen.classes[classDescriptor]
val fields = if (irClass != null) {
val declarations = irClass.declarations
declarations.mapNotNull {
when (it) {
is IrProperty -> it.backingField?.descriptor
is IrField -> it.descriptor
else -> null
}
val irClass = classDescriptor
val fields = irClass.declarations.mapNotNull {
when (it) {
is IrField -> it
is IrProperty -> it.konanBackingField
else -> null
}
} else {
val properties = classDescriptor.unsubstitutedMemberScope.
getContributedDescriptors().
filterIsInstance<DeserializedPropertyDescriptor>()
properties.mapNotNull { it.backingField }
}
return fields.sortedBy {
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 {
@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)!!
@@ -163,8 +149,8 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
val functions = mutableMapOf<FunctionDescriptor, FunctionLlvmDeclarations>()
val classes = mutableMapOf<ClassDescriptor, ClassLlvmDeclarations>()
val fields = mutableMapOf<PropertyDescriptor, FieldLlvmDeclarations>()
val staticFields = mutableMapOf<PropertyDescriptor, StaticFieldLlvmDeclarations>()
val fields = mutableMapOf<IrField, FieldLlvmDeclarations>()
val staticFields = mutableMapOf<IrField, StaticFieldLlvmDeclarations>()
var theUnitInstanceRef: ConstPointer? = null
private class Namer(val prefix: String) {
@@ -183,7 +169,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
val objectNamer = Namer("object-")
private fun getLocalName(parent: FqName, descriptor: DeclarationDescriptor): Name {
if (DescriptorUtils.isAnonymousObject(descriptor)) {
if (descriptor.isAnonymousObject) {
return objectNamer.getName(parent, descriptor)
}
@@ -191,20 +177,15 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
}
private fun getFqName(descriptor: DeclarationDescriptor): FqName {
if (descriptor is PackageFragmentDescriptor) {
return descriptor.fqName
val parent = descriptor.parent
val parentFqName = when (parent) {
is IrPackageFragment -> parent.fqName
is IrDeclaration -> getFqName(parent)
else -> error(parent)
}
val containingDeclaration = descriptor.containingDeclaration
val parent = if (containingDeclaration != null) {
getFqName(containingDeclaration)
} else {
FqName.ROOT
}
val localName = getLocalName(parent, descriptor)
return parent.child(localName)
val localName = getLocalName(parentFqName, descriptor)
return parentFqName.child(localName)
}
/**
@@ -223,17 +204,17 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
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
} else {
this.classes[declaration.descriptor] = createClassDeclarations(declaration)
this.classes[declaration] = createClassDeclarations(declaration)
}
super.visitClass(declaration)
}
private fun createClassDeclarations(declaration: IrClass): ClassLlvmDeclarations {
val descriptor = declaration.descriptor
val descriptor = declaration
val internalName = qualifyInternalName(descriptor)
@@ -317,7 +298,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
): SingletonLlvmDeclarations? {
if (descriptor.isUnit()) {
this.theUnitInstanceRef = staticData.createUnitInstance(descriptor, bodyType, typeInfoPtr)
this.theUnitInstanceRef = staticData.createUnitInstance(bodyType, typeInfoPtr)
return null
}
@@ -330,6 +311,8 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
val instanceFieldRef = addGlobal(
symbolName, getLLVMType(descriptor.defaultType), isExported = isExported, threadLocal = true)
LLVMSetInitializer(instanceFieldRef, kNullObjHeaderPtr)
return SingletonLlvmDeclarations(instanceFieldRef)
}
@@ -353,11 +336,10 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
override fun visitField(declaration: IrField) {
super.visitField(declaration)
val descriptor = declaration.descriptor
val descriptor = declaration
val dispatchReceiverParameter = descriptor.dispatchReceiverParameter
if (dispatchReceiverParameter != null) {
val containingClass = dispatchReceiverParameter.containingDeclaration
val containingClass = descriptor.containingClass
if (containingClass != null) {
val classDeclarations = this.classes[containingClass] ?: error(containingClass.toString())
val allFields = classDeclarations.fields
@@ -381,9 +363,9 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
override fun visitFunction(declaration: IrFunction) {
super.visitFunction(declaration)
if (!declaration.descriptor.kind.isReal) return
if (!declaration.isReal) return
val descriptor = declaration.descriptor
val descriptor = declaration
val llvmFunctionType = getLlvmFunctionType(descriptor)
if ((descriptor is ConstructorDescriptor && descriptor.getObjCInitMethod() != null)) {
@@ -402,7 +384,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
} else {
val symbolName = if (descriptor.isExported()) {
descriptor.symbolName.also {
if (!MainFunctionDetector.isMain(descriptor)) {
if (!descriptor.isMain()) {
assert(LLVMGetNamedFunction(context.llvm.llvmModule, it) == null) { it }
} else {
// 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 org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.isExternalObjCClassMethod
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrProperty
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.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
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 superTypeOrAny = classDesc.getSuperClassOrAny()
val superType = if (KotlinBuiltIns.isAny(classDesc)) NullPointer(runtime.typeInfoType)
val superTypeOrAny = classDesc.getSuperClassNotAny() ?: context.ir.symbols.any.owner
val superType = if (classDesc.isAny()) NullPointer(runtime.typeInfoType)
else superTypeOrAny.typeInfoPtr
val interfaces = classDesc.implementedInterfaces.map { it.typeInfoPtr }
@@ -236,14 +233,14 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
val size = 0
val superClass = context.builtIns.any
val superClass = context.ir.symbols.any.owner
assert(superClass.implementedInterfaces.isEmpty())
val interfaces = listOf(descriptor.typeInfoPtr)
val interfacesPtr = staticData.placeGlobalConstArray("",
pointerType(runtime.typeInfoType), interfaces)
assert(superClass.getMemberScope().getVariableNames().isEmpty())
assert(superClass.declarations.all { it !is IrProperty && it !is IrField })
val objOffsetsPtr = NullPointer(int32Type)
val objOffsetsCount = 0
val fieldsPtr = NullPointer(runtime.fieldTableRecordType)
@@ -295,18 +292,18 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
private fun getReflectionInfo(descriptor: ClassDescriptor): ReflectionInfo {
// Use data from value class in type info for box class:
val descriptorForReflection = context.ir.symbols.valueClassToBox.entries
.firstOrNull { it.value.descriptor == descriptor }
?.key ?: descriptor
.firstOrNull { it.value.owner == descriptor }
?.key?.owner ?: descriptor
return if (DescriptorUtils.isAnonymousObject(descriptorForReflection)) {
return if (descriptorForReflection.isAnonymousObject) {
ReflectionInfo(packageName = null, relativeName = null)
} else if (DescriptorUtils.isLocal(descriptorForReflection)) {
} else if (descriptorForReflection.isLocal) {
ReflectionInfo(packageName = null, relativeName = descriptorForReflection.name.asString())
} else {
ReflectionInfo(
packageName = descriptorForReflection.findPackage().fqName.asString(),
relativeName = descriptorForReflection.parentsWithSelf
.takeWhile { it is ClassDescriptor }.toList().reversed()
relativeName = generateSequence(descriptorForReflection, { it.parent as? ClassDescriptor })
.toList().reversed()
.joinToString(".") { it.name.asString() }
)
}
@@ -186,5 +186,5 @@ internal class StaticData(override val context: Context): ContextUtils {
*/
internal fun StaticData.createImmutableBinaryBlob(value: IrConst<String>): LLVMValueRef {
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.LLVMTypeRef
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.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.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.replace
@@ -43,12 +43,10 @@ private fun StaticData.arrayHeader(typeInfo: ConstPointer, length: Int): Struct
}
internal fun StaticData.createKotlinStringLiteral(value: String): ConstPointer {
val type = context.builtIns.stringType
val name = "kstr:" + value.globalHashBase64
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)
LLVMSetLinkage(res.llvm, LLVMLinkage.LLVMWeakAnyLinkage)
@@ -56,20 +54,13 @@ internal fun StaticData.createKotlinStringLiteral(value: String): ConstPointer {
return res
}
private fun StaticData.createRef(type: KotlinType, objHeaderPtr: ConstPointer): ConstPointer {
val llvmType = getLLVMType(type)
return if (llvmType != objHeaderPtr.llvmType) {
objHeaderPtr.bitcast(llvmType)
} else {
objHeaderPtr
}
}
private fun StaticData.createRef(objHeaderPtr: ConstPointer) = objHeaderPtr.bitcast(kObjHeaderPtr)
internal fun StaticData.createKotlinArray(arrayType: KotlinType, elements: List<LLVMValueRef>) =
createKotlinArray(arrayType, elements.map { constValue(it) }).llvm
internal fun StaticData.createKotlinArray(arrayClass: IrClass, elements: List<LLVMValueRef>) =
createKotlinArray(arrayClass, elements.map { constValue(it) }).llvm
internal fun StaticData.createKotlinArray(arrayType: KotlinType, elements: List<ConstValue>): ConstPointer {
val typeInfo = arrayType.typeInfoPtr!!
internal fun StaticData.createKotlinArray(arrayClass: IrClass, elements: List<ConstValue>): ConstPointer {
val typeInfo = arrayClass.typeInfoPtr
val bodyElementType: LLVMTypeRef = elements.firstOrNull()?.llvmType ?: int8Type
// (use [0 x i8] as body if there are no elements)
@@ -84,11 +75,11 @@ internal fun StaticData.createKotlinArray(arrayType: KotlinType, elements: List<
global.setInitializer(Struct(compositeType, arrayHeader, arrayBody))
return createRef(arrayType, objHeaderPtr)
return createRef(objHeaderPtr)
}
internal fun StaticData.createKotlinObject(type: KotlinType, body: ConstValue): ConstPointer {
val typeInfo = type.typeInfoPtr!!
internal fun StaticData.createKotlinObject(type: IrClass, body: ConstValue): ConstPointer {
val typeInfo = type.typeInfoPtr
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))
return createRef(type, objHeaderPtr)
return createRef(objHeaderPtr)
}
private fun StaticData.getArrayListClass(): ClassDescriptor {
@@ -118,7 +109,7 @@ private fun StaticData.getArrayListClass(): ClassDescriptor {
* @param length value for `length: Int` field.
*/
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>:
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()))
return createKotlinObject(type, body)
return createKotlinObject(arrayListClass, body)
}
internal fun StaticData.createUnitInstance(descriptor: ClassDescriptor,
bodyType: LLVMTypeRef,
internal fun StaticData.createUnitInstance(bodyType: LLVMTypeRef,
typeInfo: ConstPointer
): ConstPointer {
assert (descriptor.isUnit())
assert (getStructElements(bodyType).isEmpty())
val objHeader = objHeader(typeInfo)
val global = this.placeGlobal(theUnitInstanceName, objHeader, isExported = true)
@@ -157,7 +146,7 @@ internal fun StaticData.createUnitInstance(descriptor: ClassDescriptor,
internal val ContextUtils.theUnitInstanceRef: ConstPointer
get() {
val unitDescriptor = context.builtIns.unit
val unitDescriptor = context.ir.symbols.unit.owner
return if (isExternal(unitDescriptor)) {
constPointer(importGlobal(
theUnitInstanceName,
@@ -18,8 +18,9 @@ package org.jetbrains.kotlin.backend.konan.llvm
import llvm.*
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.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.declarations.IrVariable
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)
}
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 org.jetbrains.kotlin.backend.konan.descriptors.CurrentKonanModule
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.util.OperatorNameConventions
internal fun ObjCExportCodeGenerator.generateKotlinFunctionImpl(invokeMethod: FunctionDescriptor): ConstPointer {
// TODO: consider also overriding methods of `Any`.
@@ -31,7 +30,7 @@ internal fun ObjCExportCodeGenerator.generateKotlinFunctionImpl(invokeMethod: Fu
val function = generateFunction(
codegen,
codegen.getLlvmFunctionType(invokeMethod),
codegen.getLlvmFunctionType(context.ir.get(invokeMethod)),
"invokeFunction$numberOfParameters"
) {
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)
}
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)
@@ -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.konan.*
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.objc.ObjCCodeGenerator
import org.jetbrains.kotlin.backend.konan.objcexport.*
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.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.OperatorNameConventions
internal class ObjCExportCodeGenerator(
codegen: CodeGenerator,
@@ -153,7 +155,7 @@ internal class ObjCExportCodeGenerator(
val value = genValue(Lifetime.ARGUMENT)
return callFromBridge(conversion.descriptor.llvmFunction, listOf(value), resultLifetime)
return callFromBridge(conversion.owner.llvmFunction, listOf(value), resultLifetime)
}
internal fun emitRtti(
@@ -329,15 +331,16 @@ private fun ObjCExportCodeGenerator.setObjCExportTypeInfo(
val writableTypeInfoType = runtime.writableTypeInfoType!!
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.
staticData.createGlobal(
writableTypeInfoType,
descriptor.writableTypeInfoSymbolName,
irClass.writableTypeInfoSymbolName,
isExported = true
)
} else {
context.llvmDeclarations.forClass(descriptor).writableTypeInfoGlobal!!.also {
context.llvmDeclarations.forClass(irClass).writableTypeInfoGlobal!!.also {
it.setLinkage(LLVMLinkage.LLVMExternalLinkage)
}
}
@@ -356,7 +359,7 @@ private fun ObjCExportCodeGenerator.emitBoxConverter(objCValueType: ObjCValueTyp
val name = "${valueType.classFqName.shortName()}To${objCValueType.nsNumberName}"
val converter = generateFunction(codegen, kotlinToObjCFunctionType, name) {
val unboxFunction = symbols.getUnboxFunction(valueType).descriptor.llvmFunction
val unboxFunction = symbols.getUnboxFunction(valueType).owner.llvmFunction
val kotlinValue = callFromBridge(
unboxFunction,
listOf(param(0)),
@@ -385,15 +388,14 @@ private fun ObjCExportCodeGenerator.emitFunctionConverters() {
}
private fun ObjCExportCodeGenerator.generateKotlinFunctionAdapterToBlock(numberOfParameters: Int): ConstPointer {
val interfaceDescriptor = codegen.context.builtIns.getFunction(numberOfParameters)
val invokeMethod = interfaceDescriptor.unsubstitutedMemberScope.getContributedFunctions(
Name.identifier("invoke"), NoLookupLocation.FROM_BACKEND
).single()
val irInterface = context.ir.symbols.functions[numberOfParameters].owner
val invokeMethod = irInterface.declarations.filterIsInstance<IrSimpleFunction>()
.single { it.name == OperatorNameConventions.INVOKE }
val invokeImpl = generateKotlinFunctionImpl(invokeMethod)
val invokeImpl = generateKotlinFunctionImpl(invokeMethod.descriptor)
return rttiGenerator.generateSyntheticInterfaceImpl(
interfaceDescriptor,
irInterface,
mapOf(invokeMethod to invokeImpl)
)
}
@@ -414,7 +416,7 @@ private fun ObjCExportCodeGenerator.emitKotlinFunctionAdaptersToBlock() {
private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() {
setObjCExportTypeInfo(
context.builtIns.string,
constPointer(codegen.llvmFunction(context.interopBuiltIns.CreateNSStringFromKString))
constPointer(codegen.llvmFunction(context.ir.symbols.interopCreateNSStringFromKString.owner))
)
setObjCExportTypeInfo(
@@ -495,10 +497,11 @@ private fun ObjCExportCodeGenerator.generateObjCImp(
}
}
val targetIr = context.ir.get(target)
val llvmTarget = if (!isVirtual) {
codegen.llvmFunction(target)
codegen.llvmFunction(targetIr)
} else {
lookupVirtualImpl(args.first(), target)
lookupVirtualImpl(args.first(), targetIr)
}
val targetResult = callFromBridge(llvmTarget, args, Lifetime.ARGUMENT)
@@ -533,13 +536,15 @@ private fun ObjCExportCodeGenerator.generateObjCImpForArrayConstructor(
objCToKotlin(param(index + 2), typeBridge, Lifetime.ARGUMENT)
}
val targetIr = context.ir.get(target)
val arrayInstance = callFromBridge(
context.llvm.allocArrayFunction,
listOf(target.constructedClass.llvmTypeInfoPtr, kotlinValueArgs.first()),
listOf((targetIr as IrConstructor).constructedClass.llvmTypeInfoPtr, kotlinValueArgs.first()),
resultLifetime = Lifetime.ARGUMENT
)
callFromBridge(
target.llvmFunction,
targetIr.llvmFunction,
listOf(arrayInstance) + kotlinValueArgs
)
@@ -564,7 +569,7 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
val objcMsgSend = msgSender(objCFunctionType(methodBridge))
val functionType = codegen.getLlvmFunctionType(descriptor)
val functionType = codegen.getLlvmFunctionType(context.ir.get(descriptor))
val result = generateFunction(codegen, functionType, "") {
val args = mutableListOf<LLVMValueRef>()
@@ -689,7 +694,8 @@ private fun ObjCExportCodeGenerator.vtableIndex(descriptor: FunctionDescriptor):
return if (classDescriptor.isInterface) {
null
} 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 {
presentVtableBridges += vtableIndex(it)
presentMethodTableBridges += it.functionName
presentMethodTableBridges += context.ir.get(it).functionName
}
uninherited.forEach {
val vtableIndex = vtableIndex(it)
val functionName = it.functionName
val functionName = context.ir.get(it).functionName
if (vtableIndex !in presentVtableBridges || functionName !in presentMethodTableBridges) {
presentVtableBridges += vtableIndex
@@ -794,17 +800,18 @@ private fun ObjCExportCodeGenerator.createTypeAdapter(
.filter { mapper.isBaseMethod(it) && it.isOverridable }
.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 vtableSize = if (descriptor.kind == ClassKind.INTERFACE) {
-1
} else {
context.getVtableBuilder(descriptor).vtableEntries.size
context.getVtableBuilder(irClass).vtableEntries.size
}
val vtable = if (!descriptor.isInterface && !descriptor.typeInfoHasVtableAttached) {
staticData.placeGlobal("", rttiGenerator.vtable(descriptor)).also {
val vtable = if (!descriptor.isInterface && !irClass.typeInfoHasVtableAttached) {
staticData.placeGlobal("", rttiGenerator.vtable(irClass)).also {
it.setConstant(true)
}.pointer.getElementPtr(0)
} else {
@@ -812,7 +819,7 @@ private fun ObjCExportCodeGenerator.createTypeAdapter(
}
val methodTable = if (!descriptor.isInterface && descriptor.isAbstract()) {
rttiGenerator.methodTableRecords(descriptor)
rttiGenerator.methodTableRecords(irClass)
} else {
emptyList()
}
@@ -859,13 +866,16 @@ private fun ObjCExportCodeGenerator.createDirectAdapters(
val implementation = if (this.modality == Modality.ABSTRACT) {
null
} 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
.atMostOne { !(it.containingDeclaration as ClassDescriptor).isInterface }
.atMostOne { !(it.containingDeclaration as ClassDescriptor).isInterface }?.original
val inheritedAdapters = superClassMethod?.getAllRequiredDirectAdapters().orEmpty()
val requiredAdapters = method.getAllRequiredDirectAdapters()
@@ -914,7 +924,7 @@ private fun ObjCExportCodeGenerator.createObjectInstanceAdapter(
return generateObjCToKotlinMethodAdapter(methodBridge, selector) {
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))
}
}
@@ -930,7 +940,7 @@ private fun ObjCExportCodeGenerator.createEnumEntryAdapter(
return generateObjCToKotlinMethodAdapter(methodBridge, selector) {
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))
}
}
@@ -35,9 +35,10 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
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.simpleFunctions
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.transformChildrenVoid
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
@@ -48,7 +49,7 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain
val interop = context.interopBuiltIns
val symbols = context.ir.symbols
val nullableAnyType = context.builtIns.nullableAnyType
var runtimeJobDescriptor: FunctionDescriptor? = null
lateinit var runtimeJobFunction: IrSimpleFunction
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
irDeclarationContainer.declarations.transformFlat {
@@ -68,10 +69,11 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain
return expression
val job = expression.getValueArgument(3) as IrFunctionReference
val jobFunction = (job.symbol as IrSimpleFunctionSymbol).owner
val jobDescriptor = job.descriptor
val arg = jobDescriptor.valueParameters[0]
if (runtimeJobDescriptor == null) {
runtimeJobDescriptor = jobDescriptor.newCopyBuilder()
if (!::runtimeJobFunction.isInitialized) {
val runtimeJobDescriptor = jobDescriptor.newCopyBuilder()
.setReturnType(nullableAnyType)
.setValueParameters(listOf(ValueParameterDescriptorImpl(
containingDeclaration = jobDescriptor,
@@ -87,8 +89,17 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain
source = arg.source
)))
.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
val bridge = context.buildBridge(
@@ -115,22 +126,9 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain
internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
override fun lower(irClass: IrClass) {
val functions = mutableSetOf<FunctionDescriptor?>()
irClass.declarations.forEach {
when (it) {
is IrFunction -> functions.add(it.descriptor)
is IrProperty -> {
functions.add(it.getter?.descriptor)
functions.add(it.setter?.descriptor)
}
}
}
val builtBridges = mutableSetOf<IrSimpleFunction>()
irClass.descriptor.contributedMethods.forEach { functions.add(it) }
val builtBridges = mutableSetOf<FunctionDescriptor>()
functions.filterNotNull()
.filterNot { it.modality == Modality.ABSTRACT }
irClass.simpleFunctions()
.forEach { function ->
function.allOverriddenDescriptors
.map { OverriddenFunctionDescriptor(function, it) }
@@ -151,7 +149,7 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
?: return declaration
val descriptor = declaration.descriptor
val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor)
if (typeSafeBarrierDescription == null || builtBridges.contains(descriptor))
if (typeSafeBarrierDescription == null || builtBridges.contains(declaration))
return declaration
val irBuilder = context.createIrBuilder(declaration.symbol, declaration.startOffset, declaration.endOffset)
@@ -169,22 +167,13 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
startOffset = irClass.startOffset,
endOffset = irClass.endOffset,
descriptor = descriptor,
targetSymbol = irClass.findMember(descriptor.descriptor), // TODO: optimize.
targetSymbol = descriptor.descriptor.symbol,
superQualifierSymbol = irClass.symbol)
)
}
}
private fun IrClass.findMember(descriptor: FunctionDescriptor): IrFunctionSymbol {
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 :
internal object DECLARATION_ORIGIN_BRIDGE_METHOD :
IrDeclarationOriginImpl("BRIDGE_METHOD")
private fun IrBuilderWithScope.returnIfBadType(value: IrExpression,
@@ -220,17 +209,20 @@ private fun IrBlockBodyBuilder.buildTypeSafeBarrier(function: IrFunction,
private fun Context.buildBridge(startOffset: Int, endOffset: Int,
descriptor: OverriddenFunctionDescriptor, targetSymbol: IrFunctionSymbol,
superQualifierSymbol: IrClassSymbol? = null): IrFunctionImpl {
val bridgeDescriptor = specialDeclarationsFactory.getBridgeDescriptor(descriptor)
val bridge = IrFunctionImpl(startOffset, endOffset, DECLARATION_ORIGIN_BRIDGE_METHOD,
bridgeDescriptor).apply { createParameterDeclarations() }
superQualifierSymbol: IrClassSymbol? = null): IrFunction {
val bridge = specialDeclarationsFactory.getBridgeDescriptor(descriptor)
if (bridge.modality == Modality.ABSTRACT) {
return bridge
}
val irBuilder = createIrBuilder(bridge.symbol, startOffset, endOffset)
bridge.body = irBuilder.irBlockBody(bridge) {
val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor.overriddenDescriptor)
typeSafeBarrierDescription?.let { buildTypeSafeBarrier(bridge, descriptor.descriptor, it) }
val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor.overriddenDescriptor.descriptor)
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 */
).apply {
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
else
+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.konan.Context
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.push
import org.jetbrains.kotlin.backend.konan.irasdescriptors.fqNameSafe
import org.jetbrains.kotlin.backend.konan.llvm.functionName
import org.jetbrains.kotlin.descriptors.*
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.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
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.TypeUtils
@@ -69,7 +67,7 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
private var functionReferenceCount = 0
override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(object: IrElementTransformerVoidWithContext() {
irFile.transform(object: IrElementTransformerVoidWithContext() {
private val stack = mutableListOf<IrElement>()
@@ -126,7 +124,12 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
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)
return irBuilder.irBlock(expression) {
+loweredFunctionReference.functionReferenceClass
@@ -137,7 +140,7 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
}
}
}
})
}, null)
}
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 inner class FunctionReferenceBuilder(val containingDeclaration: DeclarationDescriptor,
val parent: IrDeclarationParent,
val functionReference: IrFunctionReference) {
private val functionDescriptor = functionReference.descriptor
@@ -176,12 +180,14 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
val superTypes = mutableListOf(
kFunctionImplSymbol.owner.defaultType.replace(listOf(returnType))
)
val superClasses = mutableListOf(kFunctionImplSymbol.owner)
val numberOfParameters = unboundFunctionParameters.size
val functionClassDescriptor = context.reflectionTypes.getKFunction(numberOfParameters)
val functionParameterTypes = unboundFunctionParameters.map { it.type }
val functionClassTypeParameters = functionParameterTypes + returnType
superTypes += functionClassDescriptor.defaultType.replace(functionClassTypeParameters)
superClasses += context.ir.symbols.kFunctions[numberOfParameters].owner
var suspendFunctionClassDescriptor: ClassDescriptor? = 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
suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) + lastParameterType.arguments.single().type
superTypes += suspendFunctionClassDescriptor.defaultType.replace(suspendFunctionClassTypeParameters)
superClasses += context.ir.symbols.suspendFunctions[numberOfParameters - 1].owner
}
functionReferenceClassDescriptor = ClassDescriptorImpl(
functionReferenceClassDescriptor = object : ClassDescriptorImpl(
/* containingDeclaration = */ containingDeclaration,
/* name = */ "${functionDescriptor.name}\$${functionReferenceCount++}".synthesizedName,
/* modality = */ Modality.FINAL,
@@ -202,13 +209,16 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
/* superTypes = */ superTypes,
/* source = */ SourceElement.NO_SOURCE,
/* isExternal = */ false
)
) {
override fun getVisibility() = Visibilities.PRIVATE
}
functionReferenceClass = IrClassImpl(
startOffset = startOffset,
endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
descriptor = functionReferenceClassDescriptor
)
functionReferenceClass.parent = this.parent
val constructorBuilder = createConstructorBuilder()
@@ -222,33 +232,27 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
suspendInvokeMethodBuilder = createInvokeMethodBuilder(suspendInvokeFunctionDescriptor)
}
val inheritedKFunctionImpl = kFunctionImplSymbol.descriptor.unsubstitutedMemberScope
.getContributedDescriptors()
.map { it.createFakeOverrideDescriptor(functionReferenceClassDescriptor) }
.filterNotNull()
val contributedDescriptors = (
inheritedKFunctionImpl + invokeMethodBuilder.symbol.descriptor + suspendInvokeMethodBuilder?.symbol?.descriptor
).filterNotNull().toList()
val memberScope = stub<MemberScope>("callable reference class")
functionReferenceClassDescriptor.initialize(
SimpleMemberScope(contributedDescriptors), setOf(constructorBuilder.symbol.descriptor), null)
memberScope, setOf(constructorBuilder.symbol.descriptor), null)
functionReferenceClass.createParameterDeclarations()
functionReferenceThis = functionReferenceClass.thisReceiver!!.symbol
functionReferenceClass.addFakeOverrides()
constructorBuilder.initialize()
functionReferenceClass.declarations.add(constructorBuilder.ir)
functionReferenceClass.addChild(constructorBuilder.ir)
invokeMethodBuilder.initialize()
functionReferenceClass.declarations.add(invokeMethodBuilder.ir)
functionReferenceClass.addChild(invokeMethodBuilder.ir)
suspendInvokeMethodBuilder?.let {
it.initialize()
functionReferenceClass.declarations.add(it.ir)
functionReferenceClass.addChild(it.ir)
}
functionReferenceClass.setSuperSymbolsAndAddFakeOverrides(superClasses)
return BuiltFunctionReference(functionReferenceClass, constructorBuilder.ir)
}
@@ -299,7 +303,7 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
IrConstKind.String, functionDescriptor.name.asString())
putValueArgument(0, name)
val fqName = IrConstImpl(startOffset, endOffset, context.builtIns.stringType, IrConstKind.String,
functionDescriptor.fullName)
(functionReference.symbol.owner as IrFunction).fullName)
putValueArgument(1, fqName)
val bound = IrConstImpl.boolean(startOffset, endOffset, context.builtIns.booleanType,
boundFunctionParameters.isNotEmpty())
@@ -318,17 +322,8 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
}
}
// TODO: what about private package level functions?
private val DeclarationDescriptor.fullName: String
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 val IrFunction.fullName: String
get() = parent.fqNameSafe.child(Name.identifier(functionName)).asString()
private fun createInvokeMethodBuilder(superFunctionDescriptor: FunctionDescriptor)
= object : SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
@@ -385,7 +380,10 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
val argument =
if (!unboundArgsSet.contains(it))
// Bound parameter - read from field.
irGetField(irGet(functionReferenceThis), argumentToPropertiesMap[it]!!)
irGetField(
irGet(function.dispatchReceiverParameter!!.symbol),
argumentToPropertiesMap[it]!!
)
else {
if (ourSymbol.descriptor.isSuspend && unboundIndex == valueParameters.size)
// For suspend functions the last argument is continuation and it is implicit.
@@ -420,7 +418,7 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
initialize()
}
functionReferenceClass.declarations.add(propertyBuilder.ir)
functionReferenceClass.addChild(propertyBuilder.ir)
return propertyBuilder.ir.backingField!!.symbol
}
@@ -16,10 +16,10 @@
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.IrElementVisitorVoidWithContext
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.impl.*
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.typeUtil.makeNullable
class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor,
internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor,
val parentDescriptor: DeclarationDescriptor,
val context: CommonBackendContext) {
val context: Context) {
private val descriptorSubstituteMap: MutableMap<DeclarationDescriptor, DeclarationDescriptor> = mutableMapOf()
private var typeSubstitutor: TypeSubstitutor? = null
@@ -503,7 +503,9 @@ class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor,
origin = mapDeclarationOrigin(declaration.origin),
descriptor = mapFunctionDeclaration(declaration.descriptor),
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) {
irDeclarationContainer.declarations.transformFlat { memberDeclaration ->
if (memberDeclaration is IrFunction)
lower(memberDeclaration)
lower(memberDeclaration).also { functions ->
functions.forEach {
it.parent = irDeclarationContainer
}
}
else
null
}
@@ -78,12 +82,18 @@ open class DefaultArgumentStubGenerator constructor(val context: CommonBackendCo
functionDescriptor.overriddenDescriptors.forEach { context.log{"DEFAULT-REPLACER: $it"} }
if (bodies.isNotEmpty()) {
val newIrFunction = functionDescriptor.generateDefaultsFunction(context)
newIrFunction.parent = irFunction.parent
val descriptor = newIrFunction.descriptor
log { "$functionDescriptor -> $descriptor" }
val builder = context.createIrBuilder(newIrFunction.symbol)
val body = builder.irBlockBody(irFunction) {
newIrFunction.body = builder.irBlockBody(newIrFunction) {
val params = mutableListOf<IrVariableSymbol>()
val variables = mutableMapOf<ValueDescriptor, IrValueSymbol>()
irFunction.dispatchReceiverParameter?.let {
variables[it.descriptor] = newIrFunction.dispatchReceiverParameter!!.symbol
}
if (descriptor.extensionReceiverParameter != null) {
variables[functionDescriptor.extensionReceiverParameter!!] =
newIrFunction.extensionReceiverParameter!!.symbol
@@ -157,20 +167,8 @@ open class DefaultArgumentStubGenerator constructor(val context: CommonBackendCo
irFunction.valueParameters.forEach {
it.defaultValue = null
}
return if (functionDescriptor is ClassConstructorDescriptor)
listOf(irFunction, IrConstructorImpl(
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, newIrFunction)
}
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?>>> {
val descriptor = expression.descriptor as FunctionDescriptor
val keyDescriptor = if (DescriptorUtils.isOverride(descriptor))
DescriptorUtils.getAllOverriddenDescriptors(descriptor).first { it.needsDefaultArgumentsLowering }
else
descriptor.original
private fun IrFunction.findSuperMethodWithDefaultArguments(): IrFunction? {
if (!this.descriptor.needsDefaultArgumentsLowering) return null
if (this !is IrSimpleFunction) return this
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)
realFunction.parent = keyFunction.parent
val realDescriptor = realFunction.descriptor
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.impl.*
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.functions
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -120,16 +121,14 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
declaration.transformChildrenVoid(this)
val initializer = declaration.delegate.initializer!!
return IrVariableImpl(declaration.startOffset, declaration.endOffset,
declaration.origin, declaration.delegate.descriptor,
IrBlockImpl(initializer.startOffset, initializer.endOffset, initializer.type, null,
listOf(
declaration.getter,
declaration.setter,
initializer
).filterNotNull())
)
declaration.delegate.initializer = IrBlockImpl(initializer.startOffset, initializer.endOffset, initializer.type, null,
listOf(
declaration.getter,
declaration.setter,
initializer
).filterNotNull())
return declaration.delegate
}
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
@@ -191,7 +190,7 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
if (kProperties.isNotEmpty()) {
val initializers = kProperties.values.sortedBy { it.second }.map { it.first }
// TODO: move to object for lazy initialization.
irFile.declarations.add(0, kPropertiesField.apply {
irFile.addChild(kPropertiesField.apply {
initializer = IrExpressionBodyImpl(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.FileLoweringPass
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.jvm.descriptors.createValueParameter
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.DECLARATION_ORIGIN_ENUM
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.createArrayOfExpression
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.name.Name
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.TypeSubstitutor
@@ -187,7 +186,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val defaultClass = createDefaultClassForEnumEntries()
lowerEnumClassBody()
if (defaultClass != null)
irClass.declarations.add(defaultClass)
irClass.addChild(defaultClass)
createImplObject()
}
@@ -275,15 +274,11 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
}
}
val contributedDescriptors = irClass.descriptor.unsubstitutedMemberScope
.getContributedDescriptors()
.map { it.createFakeOverrideDescriptor(defaultClassDescriptor) }
.filterNotNull()
.toList()
defaultClassDescriptor.initialize(SimpleMemberScope(contributedDescriptors), constructors, null)
val memberScope = stub<MemberScope>("enum default class")
defaultClassDescriptor.initialize(memberScope, constructors, null)
defaultClass.createParameterDeclarations()
defaultClass.addFakeOverrides()
defaultClass.setSuperSymbolsAndAddFakeOverrides(listOf(irClass))
return defaultClass
}
@@ -325,10 +320,10 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
constructorOfAny, implObject.descriptor.constructors.single(),
DECLARATION_ORIGIN_ENUM)
implObject.declarations.add(createSyntheticValuesPropertyDeclaration(enumEntries))
implObject.declarations.add(createValuesPropertyInitializer(enumEntries))
implObject.addChild(createSyntheticValuesPropertyDeclaration(enumEntries))
implObject.addChild(createValuesPropertyInitializer(enumEntries))
irClass.declarations.add(implObject)
irClass.addChild(implObject)
}
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))
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
@@ -432,6 +429,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
loweredConstructorDescriptor,
enumConstructor.body!! // will be transformed later
)
loweredEnumConstructor.parent = enumConstructor.parent
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.expressions.*
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.visitors.IrElementTransformerVoid
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.
) as IrFunction
val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl(copyFunctionDeclaration.descriptor.original)
val evaluationStatements = evaluateArguments(callee, copyFunctionDeclaration) // And list of evaluation statements.
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
if (descriptor.isInlineConstructor) {
val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall
val irBuilder = context.createIrBuilder(copyFunctionDeclaration.symbol, startOffset, endOffset)
val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
irBuilder.run {
val constructorDescriptor = delegatingConstructorCall.descriptor.original
val constructorCall = irCall(delegatingConstructorCall.symbol,
@@ -166,7 +169,7 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
startOffset = startOffset,
endOffset = endOffset,
type = returnType,
descriptor = copyFunctionDeclaration.descriptor.original,
symbol = irReturnableBlockSymbol,
origin = null,
statements = statements,
sourceFileName = sourceFileName
@@ -28,12 +28,10 @@ import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
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.*
import org.jetbrains.kotlin.ir.expressions.impl.*
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.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
@@ -118,7 +116,23 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
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
}
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.IrClass
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.IrExpression
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.symbols.IrConstructorSymbol
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.visitors.transformChildrenVoid
import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -57,7 +59,7 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
private fun createOuterThisField() {
val field = context.specialDeclarationsFactory.getOuterThisField(classDescriptor)
outerThisFieldSymbol = field.symbol
irClass.declarations.add(field)
irClass.addChild(field)
}
private fun lowerConstructors() {
@@ -109,7 +111,16 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
var innerClass: ClassDescriptor
if (constructorSymbol == null || constructorSymbol.descriptor.constructedClass != 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 {
// For constructor we have outer class as dispatchReceiverParameter.
innerClass = DescriptorUtils.getContainingClass(classDescriptor) ?:
@@ -123,7 +123,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
else -> null
}
}.let { irClass.declarations.addAll(it) }
}.let { irClass.addChildren(it) }
if (irClass.descriptor.annotations.hasAnnotation(interop.exportObjCClass.fqNameSafe)) {
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.impl.*
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.transformFlat
import org.jetbrains.kotlin.ir.visitors.*
@@ -144,6 +145,17 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
"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) {
val localFunctions: MutableMap<FunctionDescriptor, LocalFunctionContext> = LinkedHashMap()
val localClasses: MutableMap<ClassDescriptor, LocalClassContext> = LinkedHashMap()
@@ -169,6 +181,7 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
rewriteDeclarations()
val result = collectRewrittenDeclarations()
result.forEach { it.parent = memberDeclaration.parent }
return result
}
@@ -209,7 +222,14 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
// Replace local function definition with an empty composite.
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType)
} 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]
if (constructorContext != null) {
return constructorContext.transformedDeclaration.apply {
this.parent = declaration.parent
this.body = declaration.body!!
declaration.descriptor.valueParameters.filter { it.declaresDefaultValue() }.forEach { argument ->
@@ -361,7 +382,7 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
localClassContext.capturedValueToField.forEach { capturedValue, field ->
val startOffset = irClass.startOffset
val endOffset = irClass.endOffset
irClass.declarations.add(field)
irClass.addChild(field)
for (constructorContext in constructorsCallingSuper) {
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.getFunction
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.lower.*
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.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
@@ -301,6 +301,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
fun build(): BuiltCoroutine {
val superTypes = mutableListOf<KotlinType>(coroutineImplClassDescriptor.defaultType)
val superClasses = mutableListOf<IrClass>(coroutineImplSymbol.owner)
var suspendFunctionClassDescriptor: ClassDescriptor? = null
var functionClassDescriptor: ClassDescriptor? = null
var suspendFunctionClassTypeArguments: List<KotlinType>? = null
@@ -313,12 +314,14 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
val unboundParameterTypes = unboundFunctionParameters.map { it.type }
suspendFunctionClassTypeArguments = unboundParameterTypes + irFunction.descriptor.returnType!!
superTypes += suspendFunctionClassDescriptor.defaultType.replace(suspendFunctionClassTypeArguments)
superClasses += context.ir.symbols.suspendFunctions[numberOfParameters].owner
functionClassDescriptor = kotlinPackageScope.getContributedClassifier(
Name.identifier("Function${numberOfParameters + 1}"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
val continuationType = continuationClassDescriptor.defaultType.replace(listOf(irFunction.descriptor.returnType!!))
functionClassTypeArguments = unboundParameterTypes + continuationType + context.builtIns.nullableAnyType
superTypes += functionClassDescriptor.defaultType.replace(functionClassTypeArguments)
superClasses += context.ir.symbols.functions[numberOfParameters + 1].owner
}
coroutineClassDescriptor = ClassDescriptorImpl(
@@ -336,6 +339,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
descriptor = coroutineClassDescriptor
)
coroutineClass.parent = irFunction.parent
val overriddenMap = mutableMapOf<CallableMemberDescriptor, CallableMemberDescriptor>()
@@ -375,40 +379,35 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
doResumeFunctionSymbol = doResumeMethodBuilder.symbol)
}
val inheritedFromCoroutineImpl = coroutineImplClassDescriptor.unsubstitutedMemberScope
.getContributedDescriptors()
.map { overriddenMap[it] ?: it.createFakeOverrideDescriptor(coroutineClassDescriptor) }
val contributedDescriptors = (
inheritedFromCoroutineImpl + invokeMethodBuilder?.symbol?.descriptor
).filterNotNull().toList()
coroutineClassDescriptor.initialize(SimpleMemberScope(contributedDescriptors), constructors, null)
val memberScope = stub<MemberScope>("coroutine class")
coroutineClassDescriptor.initialize(memberScope, constructors, null)
coroutineClass.createParameterDeclarations()
coroutineClassThis = coroutineClass.thisReceiver!!.symbol
coroutineClass.addFakeOverrides()
coroutineConstructorBuilder.initialize()
coroutineClass.declarations.add(coroutineConstructorBuilder.ir)
coroutineClass.addChild(coroutineConstructorBuilder.ir)
coroutineFactoryConstructorBuilder?.let {
it.initialize()
coroutineClass.declarations.add(it.ir)
coroutineClass.addChild(it.ir)
}
createMethodBuilder?.let {
it.initialize()
coroutineClass.declarations.add(it.ir)
coroutineClass.addChild(it.ir)
}
invokeMethodBuilder?.let {
it.initialize()
coroutineClass.declarations.add(it.ir)
coroutineClass.addChild(it.ir)
}
doResumeMethodBuilder.initialize()
coroutineClass.declarations.add(doResumeMethodBuilder.ir)
coroutineClass.addChild(doResumeMethodBuilder.ir)
coroutineClass.setSuperSymbolsAndAddFakeOverrides(superClasses)
return BuiltCoroutine(
coroutineClass = coroutineClass,
@@ -569,6 +568,8 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
createParameterDeclarations()
val thisReceiver = this.dispatchReceiverParameter!!.symbol
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn(
@@ -579,7 +580,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
if (unboundArgsSet.contains(it))
irGet(valueParameters[unboundIndex++].symbol)
else
irGetField(irGet(coroutineClassThis), argumentToPropertiesMap[it]!!)
irGetField(irGet(thisReceiver), argumentToPropertiesMap[it]!!)
}.forEachIndexed { index, argument ->
putValueArgument(index, argument)
}
@@ -640,12 +641,14 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
createParameterDeclarations()
val thisReceiver = this.dispatchReceiverParameter!!.symbol
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn(
irCall(doResumeFunctionSymbol).apply {
dispatchReceiver = irCall(createFunctionSymbol).apply {
dispatchReceiver = irGet(coroutineClassThis)
dispatchReceiver = irGet(thisReceiver)
valueParameters.forEachIndexed { index, parameter ->
putValueArgument(index, irGet(parameter.symbol))
}
@@ -673,7 +676,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
initialize()
}
coroutineClass.declarations.add(propertyBuilder.ir)
coroutineClass.addChild(propertyBuilder.ir)
return propertyBuilder.symbol
}
@@ -709,7 +712,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
outType = context.builtIns.nullableAnyType,
isMutable = true)
)
val label = coroutineClassDescriptor.unsubstitutedMemberScope
val label = coroutineImplClassDescriptor.unsubstitutedMemberScope
.getContributedVariables(Name.identifier("label"), NoLookupLocation.FROM_BACKEND).single()
val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset)
@@ -747,6 +750,8 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
originalBody.transformChildrenVoid(object : IrElementTransformerVoid() {
private val thisReceiver = function.dispatchReceiverParameter!!.symbol
// Replace returns to refer to the new function.
override fun visitReturn(expression: IrReturn): IrExpression {
expression.transformChildrenVoid(this)
@@ -763,7 +768,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
val capturedValue = argumentToPropertiesMap[expression.descriptor]
?: return expression
return irGetField(irGet(coroutineClassThis), capturedValue)
return irGetField(irGet(thisReceiver), capturedValue)
}
// Save/restore state at suspension points.
@@ -782,10 +787,10 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
val scope = liveLocals[suspensionPoint]!!
return irBlock(expression) {
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 {
dispatchReceiver = irGet(coroutineClassThis)
dispatchReceiver = irGet(thisReceiver)
putValueArgument(0, irGet(suspensionPoint.suspensionPointIdParameter.symbol))
}
}
@@ -794,7 +799,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
val scope = liveLocals[suspensionPoint]!!
return irBlock(expression) {
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,
type = context.builtIns.unitType,
suspensionPointId = irCall(coroutineImplLabelGetterSymbol).apply {
dispatchReceiver = irGet(coroutineClassThis)
dispatchReceiver = irGet(function.dispatchReceiverParameter!!.symbol)
},
result = irBlock(startOffset, endOffset) {
+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.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.util.addFakeOverrides
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.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
@@ -499,6 +496,7 @@ internal class TestProcessor (val context: KonanBackendContext) {
addMember(instanceGetterBuilder.ir)
companionGetterBuilder?.let { addMember(it.ir) }
addFakeOverrides()
setSuperSymbols(context.ir.symbols.symbolTable)
}
override fun doInitialize() {
@@ -546,7 +544,7 @@ internal class TestProcessor (val context: KonanBackendContext) {
irFile.packageFragmentDescriptor,
testClass.functions)) {
initialize()
irFile.declarations.add(ir)
irFile.addChild(ir)
irFile.addTopLevelInitializer(
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.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.correspondingValueType
import org.jetbrains.kotlin.backend.konan.descriptors.isArray
@@ -33,7 +34,7 @@ import org.jetbrains.kotlin.types.typeUtil.isUnit
internal interface ObjCExportMapper {
fun getCategoryMembersFor(descriptor: ClassDescriptor): List<CallableMemberDescriptor>
val maxFunctionTypeParameterCount get() = 22
val maxFunctionTypeParameterCount get() = KONAN_FUNCTION_INTERFACES_MAX_PARAMETERS
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.Context
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
import org.jetbrains.kotlin.backend.konan.llvm.findMainEntryPoint
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
internal class CallGraphNode(val graph: CallGraph, val symbol: DataFlowIR.FunctionSymbol)
@@ -94,7 +93,7 @@ internal class CallGraphBuilder(val context: Context,
fun build(): CallGraph {
val rootSet = if (hasMain) {
listOf(symbolTable.mapFunction(findMainEntryPoint(context)!!).resolved()) +
listOf(symbolTable.mapFunction(context.ir.symbols.entryPoint!!.owner).resolved()) +
moduleDFG.functions
.map { it.key }
.filter { it.isGlobalInitializer }
@@ -16,69 +16,60 @@
package org.jetbrains.kotlin.backend.konan.optimizations
import org.jetbrains.kotlin.backend.common.descriptors.allParameters
import org.jetbrains.kotlin.backend.common.descriptors.isSuspend
import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole
import org.jetbrains.kotlin.backend.common.peek
import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.allOverriddenDescriptors
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.backend.konan.descriptors.target
import org.jetbrains.kotlin.backend.konan.ir.IrSuspendableExpression
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.localHash
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
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.util.getArguments
import org.jetbrains.kotlin.ir.util.simpleFunctions
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.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.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.util.OperatorNameConventions
private fun computeErasure(type: KotlinType, erasure: MutableList<ClassDescriptor>) {
val descriptor = type.constructor.declarationDescriptor
when (descriptor) {
is ClassDescriptor -> erasure += descriptor
is TypeParameterDescriptor -> {
private fun computeErasure(type: KotlinType, context: Context, erasure: MutableList<ClassDescriptor>) {
val irClass = context.ir.getClass(type)
if (irClass != null) {
erasure += irClass
} else {
val descriptor = type.constructor.declarationDescriptor
if (descriptor is TypeParameterDescriptor) {
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>()
computeErasure(this, result)
computeErasure(this, context, result)
return result
}
private fun MemberScope.getOverridingOf(function: FunctionDescriptor) = when (function) {
is PropertyGetterDescriptor ->
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 IrClass.getOverridingOf(function: FunctionDescriptor) = (function as? SimpleFunctionDescriptor)?.let {
it.allOverriddenDescriptors.atMostOne { it.parent == this }
}
private fun IrTypeOperator.isCast() =
@@ -122,7 +113,7 @@ private class VariableValues {
if (element !is IrGetValue)
result += element
else {
val descriptor = element.descriptor
val descriptor = element.symbol.owner
if (descriptor is VariableDescriptor && !seen.contains(descriptor))
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>>) {
fun forEachValue(expression: IrExpression, block: (IrExpression) -> Unit) {
@@ -187,11 +179,14 @@ private class ExpressionValuesExtractor(val returnableBlockValues: Map<IrReturna
is IrSetField -> block(expression)
else -> {
if ((expression.type.isUnit() || expression.type.isNothing())) {
block(IrGetObjectValueImpl(expression.startOffset, expression.endOffset,
expression.type, IrClassSymbolImpl(expression.type.constructor.declarationDescriptor as ClassDescriptor)))
val classSymbol = when {
expression.type.isUnit() -> context.ir.symbols.unit
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.
private val suspendableExpressionValues = mutableMapOf<IrSuspendableExpression, MutableList<IrSuspensionPoint>>()
private val expressionValuesExtractor = ExpressionValuesExtractor(returnableBlockValues, suspendableExpressionValues)
private val expressionValuesExtractor = ExpressionValuesExtractor(context, returnableBlockValues, suspendableExpressionValues)
fun build(): ModuleDFG {
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("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("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.
val visitor = ElementFinderVisitor()
body.acceptVoid(visitor)
@@ -346,14 +341,13 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
if (expression is IrCall && expression.symbol == scheduleImplSymbol) {
// Producer of scheduleImpl is called externally, we need to reflect this somehow.
@Suppress("DEPRECATION")
val producerInvocation = IrCallImpl(expression.startOffset, expression.endOffset, scheduleImplProducerInvokeDescriptor)
val producerInvocation = IrCallImpl(expression.startOffset, expression.endOffset,
scheduleImplProducerInvoke.symbol, scheduleImplProducerInvoke.descriptor)
producerInvocation.dispatchReceiver = expression.getValueArgument(2)
expressions += producerInvocation
}
if (expression is IrReturnableBlock) {
returnableBlocks.put(expression.descriptor, expression)
returnableBlockValues.put(expression, mutableListOf())
}
if (expression is IrSuspendableExpression) {
@@ -363,8 +357,6 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
if (expression is IrSuspensionPoint)
suspendableExpressionValues[suspendableExpressionStack.peek()!!]!!.add(expression)
super.visitExpression(expression)
if (expression is IrReturnableBlock)
returnableBlocks.remove(expression.descriptor)
if (expression is IrSuspendableExpression)
suspendableExpressionStack.pop()
}
@@ -375,7 +367,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
}
override fun visitReturn(expression: IrReturn) {
val returnableBlock = returnableBlocks[expression.returnTarget]
val returnableBlock = expression.returnTargetSymbol.owner as? IrReturnableBlock
if (returnableBlock != null) {
returnableBlockValues[returnableBlock]!!.add(expression.value)
} else { // Non-local return.
@@ -391,39 +383,43 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
}
override fun visitCatch(aCatch: IrCatch) {
catchParameters.add(aCatch.parameter)
catchParameters.add(aCatch.catchParameter)
super.visitCatch(aCatch)
}
override fun visitSetVariable(expression: IrSetVariable) {
super.visitSetVariable(expression)
assignVariable(expression.descriptor, expression.value)
assignVariable(expression.symbol.owner, expression.value)
}
override fun visitVariable(declaration: IrVariable) {
variableValues.addEmpty(declaration.descriptor)
variableValues.addEmpty(declaration)
super.visitVariable(declaration)
declaration.initializer?.let { assignVariable(declaration.descriptor, it) }
declaration.initializer?.let { assignVariable(declaration, it) }
}
}
private val doResumeFunctionDescriptor = context.getInternalClass("CoroutineImpl").unsubstitutedMemberScope
.getContributedFunctions(Name.identifier("doResume"), NoLookupLocation.FROM_BACKEND).single()
private val doResumeFunctionSymbol =
context.ir.symbols.coroutineImpl.owner.declarations
.filterIsInstance<IrSimpleFunction>().single { it.name.asString() == "doResume" }.symbol
private val getContinuationSymbol = context.ir.symbols.getContinuation
private val continuationType = getContinuationSymbol.descriptor.returnType!!
private val arrayGetSymbol = context.ir.symbols.arrayGet
private val arraySetSymbol = context.ir.symbols.arraySet
private val scheduleImplSymbol = context.ir.symbols.scheduleImpl
private val scheduleImplProducerClassSymbol = context.ir.symbols.functions[0]
private val scheduleImplProducerParam = scheduleImplSymbol.descriptor.valueParameters[2].also {
assert(it.name.asString() == "producer")
assert(it.type.constructor.declarationDescriptor == scheduleImplProducerClassSymbol.descriptor)
}
private val scheduleImplProducerInvokeDescriptor = scheduleImplProducerParam.type.memberScope
.getContributedFunctions(Name.identifier("invoke"), NoLookupLocation.FROM_BACKEND).single()
private val scheduleImplProducerInvoke = scheduleImplProducerClassSymbol.owner.simpleFunctions()
.single { it.name == OperatorNameConventions.INVOKE }
private inner class FunctionDFGBuilder(val expressionValuesExtractor: ExpressionValuesExtractor,
val variableValues: VariableValues,
val descriptor: CallableDescriptor,
val descriptor: DeclarationDescriptor,
val expressions: List<IrExpression>,
val returnValues: 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 templateParameters = allParameters.withIndex().associateBy({ it.value }, { DataFlowIR.Node.Parameter(it.index) })
private val continuationParameter =
if (descriptor.isSuspend)
DataFlowIR.Node.Parameter(allParameters.size)
else {
if (doResumeFunctionDescriptor in descriptor.overriddenDescriptors) // <this> is a CoroutineImpl inheritor.
templateParameters[descriptor.dispatchReceiverParameter!!] // It is its own continuation.
else null
}
private val continuationParameter = if (descriptor !is IrSimpleFunction) {
null
} else if (descriptor.isSuspend) {
DataFlowIR.Node.Parameter(allParameters.size)
} else if (doResumeFunctionSymbol in descriptor.overriddenSymbols) { // <this> is a CoroutineImpl inheritor.
templateParameters[descriptor.dispatchReceiverParameter!!] // It is its own continuation.
} else {
null
}
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 {
if (erasure.size == 1) return erasure[0]
// 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 {
val isSuspend = descriptor is IrSimpleFunction && descriptor.isSuspend
expressions.forEach { getNode(it) }
val returnNodeType = when (descriptor) {
is IrField -> descriptor.type
is IrFunction -> descriptor.returnType
else -> error(descriptor)
}
val returnsNode = DataFlowIR.Node.Variable(
values = returnValues.map { expressionToEdge(it) },
type = symbolTable.mapType(descriptor.returnType ?: context.builtIns.unitType),
type = symbolTable.mapType(returnNodeType),
kind = DataFlowIR.VariableKind.Temporary
)
val throwsNode = DataFlowIR.Node.Variable(
values = thrownValues.map { expressionToEdge(it) },
type = symbolTable.mapClass(context.builtIns.throwable),
type = symbolTable.mapClass(context.ir.symbols.throwable.owner),
kind = DataFlowIR.VariableKind.Temporary
)
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 +
(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()))
.map { symbolTable.mapClass(choosePrimary(it.erasure())) }
val parameterTypes = (allParameters.map { it.type } + (if (isSuspend) listOf(continuationType) else emptyList()))
.map { symbolTable.mapClass(choosePrimary(it.erasure(context))) }
.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(
symbol = symbolTable.mapFunction(descriptor),
parameterTypes = parameterTypes,
@@ -499,10 +505,10 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
private fun getNode(expression: IrExpression): DataFlowIR.Node {
if (expression is IrGetValue) {
val descriptor = expression.descriptor
if (descriptor is ParameterDescriptor)
val descriptor = expression.symbol.owner
if (descriptor is IrValueParameter)
return templateParameters[descriptor]!!
return variables[descriptor as VariableDescriptor]!!
return variables[descriptor]!!
}
return nodes.getOrPut(expression) {
DEBUG_OUTPUT(0) {
@@ -541,7 +547,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
symbolTable.mapType(value.type),
if (value.type.isNothing()) // <Nothing> is not a singleton though its instance is get with <IrGetObject> operation.
null
else symbolTable.mapFunction(value.descriptor.constructors.single())
else symbolTable.mapFunction(value.symbol.owner.constructors.single())
)
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)!!))
else -> {
val callee = value.descriptor
val callee = value.symbol.owner as IrFunction
val arguments = value.getArguments()
.map { expressionToEdge(it.second) }
.let {
@@ -580,11 +586,11 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
symbolTable.mapClass(owner),
callee.functionName.localHash.value,
arguments,
symbolTable.mapType(callee.returnType!!),
symbolTable.mapType(callee.returnType),
value
)
} 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" })
DataFlowIR.Node.VtableCall(
symbolTable.mapFunction(callee.target),
@@ -596,7 +602,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
)
}
} else {
val actualCallee = (value.superQualifier?.unsubstitutedMemberScope?.getOverridingOf(callee) ?: callee).target
val actualCallee = (value.superQualifierSymbol?.owner?.getOverridingOf(callee) ?: callee).target
DataFlowIR.Node.StaticCall(
symbolTable.mapFunction(actualCallee),
arguments,
@@ -611,12 +617,12 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
is IrDelegatingConstructorCall -> {
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 }
DataFlowIR.Node.StaticCall(
symbolTable.mapFunction(value.descriptor),
symbolTable.mapFunction(value.symbol.owner),
arguments.map { expressionToEdge(it) },
symbolTable.mapClass(context.builtIns.unit),
symbolTable.mapClass(context.ir.symbols.unit.owner),
symbolTable.mapType(thiz.type),
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.descriptors.isAbstract
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.isValueType
import org.jetbrains.kotlin.backend.konan.llvm.functionName
import org.jetbrains.kotlin.backend.konan.llvm.isExported
import org.jetbrains.kotlin.backend.konan.llvm.localHash
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.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass
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.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
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
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_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 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 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()
var privateTypeIndex = 0
@@ -448,17 +447,17 @@ internal object DataFlowIR {
}
override fun visitFunction(declaration: IrFunction) {
declaration.body?.let { mapFunction(declaration.descriptor) }
declaration.body?.let { mapFunction(declaration) }
}
override fun visitField(declaration: IrField) {
declaration.initializer?.let { mapFunction(declaration.descriptor) }
declaration.initializer?.let { mapFunction(declaration) }
}
override fun visitClass(declaration: IrClass) {
declaration.acceptChildrenVoid(this)
mapClass(declaration.descriptor)
mapClass(declaration)
}
}, data = null)
}
@@ -501,40 +500,27 @@ internal object DataFlowIR {
return type
}
fun mapType(type: KotlinType) = mapClass(type.erasure().single())
fun mapType(type: KotlinType) = mapClass(type.erasure(context).single())
// TODO: use from LlvmDeclarations.
private fun getFqName(descriptor: DeclarationDescriptor): FqName {
if (descriptor is PackageFragmentDescriptor) {
return descriptor.fqName
}
val containingDeclaration = descriptor.containingDeclaration
val parent = if (containingDeclaration != null) {
getFqName(containingDeclaration)
} else {
FqName.ROOT
}
val localName = descriptor.name
return parent.child(localName)
}
private fun getFqName(descriptor: DeclarationDescriptor): FqName =
descriptor.parent.fqNameSafe.child(descriptor.name)
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) {
when (it) {
is PropertyDescriptor -> {
is IrField -> {
// 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" })
}
is FunctionDescriptor -> {
val name = if (it.isExported()) it.symbolName else it.internalName
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 pointsToAnnotation = it.annotations.findAnnotation(FQ_NAME_POINTS_TO)
@Suppress("UNCHECKED_CAST")
@@ -544,7 +530,7 @@ internal object DataFlowIR {
FunctionSymbol.External(name.localHash.value, numberOfParameters, false, escapesBitMask,
pointsToBitMask?.let { it.map { it.value }.toIntArray() }, takeName { name })
} else {
val isAbstract = it.modality == Modality.ABSTRACT
val isAbstract = it is SimpleFunctionDescriptor && it.modality == Modality.ABSTRACT
val classDescriptor = it.containingDeclaration as? ClassDescriptor
val placeToFunctionsTable = !isAbstract && it !is ConstructorDescriptor && classDescriptor != null
&& classDescriptor.kind != ClassKind.ANNOTATION_CLASS
@@ -66,7 +66,7 @@ internal object Devirtualization {
return this
}
val entryPoint = findMainEntryPoint(context)
val entryPoint = context.ir.symbols.entryPoint?.owner
val exportedFunctions =
if (entryPoint != null)
listOf(moduleDFG.symbolTable.mapFunction(entryPoint).resolved())
@@ -97,7 +97,7 @@ internal object Devirtualization {
val moduleDFG: ModuleDFG,
val externalModulesDFG: ExternalModulesDFG) {
private val entryPoint = findMainEntryPoint(context)
private val entryPoint = context.ir.symbols.entryPoint?.owner
private val symbolTable = moduleDFG.symbolTable
@@ -506,7 +506,7 @@ internal object Devirtualization {
}
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
.asSequence()
.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.DirectedGraphMultiNode
import org.jetbrains.kotlin.backend.konan.llvm.Lifetime
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement
internal object EscapeAnalysis {
@@ -605,7 +604,7 @@ internal object EscapeAnalysis {
reachable += parameters.size
reachabilities.add(reachable.toIntArray())
visited.forEach { node ->
if (node !is ParameterDescriptor)
if (node !is DataFlowIR.Node.Parameter)
nodes[node]!!.addIncomingParameter(it.index)
}
}
@@ -16,27 +16,30 @@
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.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.declarations.IrFunction
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.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
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) {
is FunctionDescriptor
-> this.symbolName
-> this.uniqueName
is PropertyDescriptor
-> this.symbolName
-> this.uniqueName
is ClassDescriptor
-> this.typeInfoSymbolName
-> this.uniqueName
else -> error("Unexpected exported descriptor: $this")
}
@@ -91,3 +94,203 @@ val IrBuiltIns.irBuiltInDescriptors
.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.util.addFakeOverrides
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.KonanIr
import org.jetbrains.kotlin.serialization.KonanIr.IrConst.ValueCase.*
@@ -1209,6 +1211,7 @@ internal class IrDeserializer(val context: Context,
clazz.createParameterDeclarations()
clazz.addFakeOverrides()
clazz.setSuperSymbols(context.ir.symbols.symbolTable)
return clazz
@@ -1222,6 +1225,7 @@ internal class IrDeserializer(val context: Context,
descriptor, body as IrBody)
function.createParameterDeclarations()
function.setOverrides(context.ir.symbols.symbolTable)
proto.defaultArgumentList.forEach {
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.konan.Context
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrAnonymousInitializer
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.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrBindableSymbol
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.symbols.*
import org.jetbrains.kotlin.ir.visitors.*
@Deprecated("")
@@ -93,7 +86,7 @@ private fun IrModuleFragment.mergeFrom(other: IrModuleFragment): Unit {
if (thisPackage == null) {
this.externalPackageFragments.add(it)
} else {
thisPackage.declarations.addAll(it.declarations)
thisPackage.addChildren(it.declarations)
}
}
}
@@ -120,42 +113,47 @@ private class IrUnboundSymbolReplacer(
val descriptorToSymbol: Map<DeclarationDescriptor, IrSymbol>
) : 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? {
if (this.isBound) {
return null
}
localDescriptorToSymbol[this.descriptor]?.lastOrNull()?.let {
return it as S
}
descriptorToSymbol[this.descriptor]?.let {
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
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? {
return if (this.isBound) {
null
} 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 {
val symbol = expression.symbol.let {
if (it.isBound) {
return super.visitClassReference(expression)
}
descriptorToSymbol[it.descriptor]?.let {
it as IrClassifierSymbol
}
symbolTable.referenceClassifier(it.descriptor)
}
val symbol = expression.symbol.replace(SymbolTable::referenceClassifier)
?: return super.visitClassReference(expression)
expression.transformChildrenVoid(this)
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 {
val symbol = expression.symbol.replaceOrSame(SymbolTable::referenceField)
@@ -358,7 +359,20 @@ private class IrUnboundSymbolReplacer(
override fun visitFunction(declaration: IrFunction): IrStatement {
returnTargetStack.push(declaration.symbol)
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 {
returnTargetStack.pop()
}
@@ -17,23 +17,25 @@
package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
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.types.KotlinType
import java.lang.reflect.Proxy
//TODO: delete file on next kotlin dependency update
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)
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
# Download artifacts of https://teamcity.jetbrains.com/viewType.html?buildTypeId=Kotlin_120_Compiler
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
kotlinCompilerVersion=1.2.40-dev-610
kotlinScriptRuntimeVersion=1.2.40-dev-610
kotlinStdLibVersion=1.2.40-dev-610
kotlinReflectVersion=1.2.40-dev-610
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-837
kotlinScriptRuntimeVersion=1.2.40-dev-837
kotlinStdLibVersion=1.2.40-dev-837
kotlinReflectVersion=1.2.40-dev-837
konanVersion=0.6.1
org.gradle.jvmargs='-Dfile.encoding=UTF-8'
##
# required for performance mesuarement tasks
kotlinStdLibJdk8Version=1.2.40-dev-610
kotlinGradlePluginVersion=1.2.40-dev-610
kotlinStdLibJdk8Version=1.2.40-dev-837
kotlinGradlePluginVersion=1.2.40-dev-837