[K/N][IR][codegen] Use LazyIr for cached libraries

It's not that simple because we still need inline functions bodies
and classes fields which aren't present in Lazy IR. To overcome this,
save additional binary info for a cached library and then use it when needed
This commit is contained in:
Igor Chevdar
2021-08-24 21:14:52 +05:00
parent f865238062
commit 0cece79856
31 changed files with 1042 additions and 140 deletions
@@ -182,7 +182,7 @@ class FunctionInlining(
val statements = (copiedCallee.body as IrBlockBody).statements val statements = (copiedCallee.body as IrBlockBody).statements
val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl() val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl()
val endOffset = callee.endOffset val endOffset = statements.lastOrNull()?.endOffset ?: callee.endOffset
/* creates irBuilder appending to the end of the given returnable block: thus why we initialize /* creates irBuilder appending to the end of the given returnable block: thus why we initialize
* irBuilder with (..., endOffset, endOffset). * irBuilder with (..., endOffset, endOffset).
*/ */
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
import org.jetbrains.kotlin.ir.util.DeserializableClass import org.jetbrains.kotlin.ir.util.DeserializableClass
import org.jetbrains.kotlin.ir.util.TypeTranslator import org.jetbrains.kotlin.ir.util.TypeTranslator
import org.jetbrains.kotlin.ir.util.isObject
import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolver import org.jetbrains.kotlin.metadata.deserialization.NameResolver
@@ -79,7 +80,8 @@ class IrLazyClass(
private fun shouldBuildStub(descriptor: DeclarationDescriptor): Boolean = private fun shouldBuildStub(descriptor: DeclarationDescriptor): Boolean =
descriptor !is DeclarationDescriptorWithVisibility || descriptor !is DeclarationDescriptorWithVisibility ||
!DescriptorVisibilities.isPrivate(descriptor.visibility) !DescriptorVisibilities.isPrivate(descriptor.visibility) ||
isObject && descriptor is ClassConstructorDescriptor
override var typeParameters: List<IrTypeParameter> by lazyVar(stubGenerator.lock) { override var typeParameters: List<IrTypeParameter> by lazyVar(stubGenerator.lock) {
descriptor.declaredTypeParameters.mapTo(arrayListOf()) { descriptor.declaredTypeParameters.mapTo(arrayListOf()) {
@@ -7,11 +7,15 @@ package org.jetbrains.kotlin.ir.declarations.lazy
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.DescriptorVisibility import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrBody import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
import org.jetbrains.kotlin.ir.util.TypeTranslator import org.jetbrains.kotlin.ir.util.TypeTranslator
@@ -20,6 +24,35 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
@OptIn(ObsoleteDescriptorBasedAPI::class)
class IrLazyValueParameter(
override val startOffset: Int,
override val endOffset: Int,
override var origin: IrDeclarationOrigin,
override val symbol: IrValueParameterSymbol,
override val descriptor: ValueParameterDescriptor,
override val name: Name,
override val index: Int,
override var type: IrType,
override var varargElementType: IrType?,
override val isCrossinline: Boolean,
override val isNoinline: Boolean,
override val isHidden: Boolean,
override val isAssignable: Boolean,
override val stubGenerator: DeclarationStubGenerator,
override val typeTranslator: TypeTranslator,
) : IrValueParameter(), IrLazyDeclarationBase {
override lateinit var parent: IrDeclarationParent
override var defaultValue: IrExpressionBody? = null
override var annotations: List<IrConstructorCall> by createLazyAnnotations()
init {
symbol.bind(this)
}
}
@OptIn(ObsoleteDescriptorBasedAPI::class) @OptIn(ObsoleteDescriptorBasedAPI::class)
class IrLazyConstructor( class IrLazyConstructor(
override val startOffset: Int, override val startOffset: Int,
@@ -5,10 +5,7 @@
package org.jetbrains.kotlin.ir.declarations.lazy package org.jetbrains.kotlin.ir.declarations.lazy
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.ir.IrLock import org.jetbrains.kotlin.ir.IrLock
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
@@ -32,6 +29,16 @@ class IrLazySymbolTable(private val originalTable: SymbolTable) : ReferenceSymbo
} }
} }
override fun referenceTypeAlias(descriptor: TypeAliasDescriptor): IrTypeAliasSymbol {
synchronized(lock) {
return originalTable.referenceTypeAlias(descriptor).also {
if (!it.isBound) {
stubGenerator?.generateTypeAliasStub(descriptor)
}
}
}
}
override fun referenceConstructor(descriptor: ClassConstructorDescriptor): IrConstructorSymbol { override fun referenceConstructor(descriptor: ClassConstructorDescriptor): IrConstructorSymbol {
synchronized(lock) { synchronized(lock) {
return originalTable.referenceConstructor(descriptor).also { return originalTable.referenceConstructor(descriptor).also {
@@ -62,6 +69,16 @@ class IrLazySymbolTable(private val originalTable: SymbolTable) : ReferenceSymbo
} }
} }
override fun referenceProperty(descriptor: PropertyDescriptor): IrPropertySymbol {
synchronized(lock) {
return originalTable.referenceProperty(descriptor).also {
if (!it.isBound) {
stubGenerator?.generatePropertyStub(descriptor)
}
}
}
}
override fun referenceTypeParameter(classifier: TypeParameterDescriptor): IrTypeParameterSymbol { override fun referenceTypeParameter(classifier: TypeParameterDescriptor): IrTypeParameterSymbol {
synchronized(lock) { synchronized(lock) {
return originalTable.referenceTypeParameter(classifier).also { return originalTable.referenceTypeParameter(classifier).also {
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
import org.jetbrains.kotlin.ir.symbols.IrFileSymbol import org.jetbrains.kotlin.ir.symbols.IrFileSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
import org.jetbrains.kotlin.ir.util.file import org.jetbrains.kotlin.ir.util.fileOrNull
import org.jetbrains.kotlin.ir.util.transformInPlace import org.jetbrains.kotlin.ir.util.transformInPlace
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
@@ -58,6 +58,5 @@ abstract class IrReturnableBlock : IrBlock(), IrSymbolOwner, IrReturnTarget {
abstract val inlineFunctionSymbol: IrFunctionSymbol? abstract val inlineFunctionSymbol: IrFunctionSymbol?
} }
@Suppress("unused") // Used in kotlin-native
val IrReturnableBlock.sourceFileSymbol: IrFileSymbol? val IrReturnableBlock.sourceFileSymbol: IrFileSymbol?
get() = inlineFunctionSymbol?.owner?.file?.symbol get() = inlineFunctionSymbol?.owner?.fileOrNull?.symbol
@@ -66,7 +66,7 @@ fun buildFakeOverrideMember(superType: IrType, member: IrOverridableMember, claz
val typeParameters = extractTypeParameters(classifier.owner) val typeParameters = extractTypeParameters(classifier.owner)
val superArguments = superType.arguments val superArguments = superType.arguments
assert(typeParameters.size == superArguments.size) { require(typeParameters.size == superArguments.size) {
"typeParameters = $typeParameters size != typeArguments = $superArguments size " "typeParameters = $typeParameters size != typeArguments = $superArguments size "
} }
@@ -76,7 +76,7 @@ fun buildFakeOverrideMember(superType: IrType, member: IrOverridableMember, claz
val tp = typeParameters[i] val tp = typeParameters[i]
val ta = superArguments[i] val ta = superArguments[i]
require(ta is IrTypeProjection) { "Unexpected super type argument: ${ta.render()} @ $i" } require(ta is IrTypeProjection) { "Unexpected super type argument: ${ta.render()} @ $i" }
assert(ta.variance == Variance.INVARIANT) { "Unexpected variance in super type argument: ${ta.variance} @$i" } require(ta.variance == Variance.INVARIANT) { "Unexpected variance in super type argument: ${ta.variance} @$i" }
substitutionMap[tp.symbol] = ta.type substitutionMap[tp.symbol] = ta.type
} }
@@ -414,7 +414,7 @@ class IrOverridingUtil(
fakeOverride.overriddenSymbols = effectiveOverridden.map { it.original.symbol } fakeOverride.overriddenSymbols = effectiveOverridden.map { it.original.symbol }
assert( require(
fakeOverride.overriddenSymbols.isNotEmpty() fakeOverride.overriddenSymbols.isNotEmpty()
) { "Overridden symbols should be set for " + CallableMemberDescriptor.Kind.FAKE_OVERRIDE } ) { "Overridden symbols should be set for " + CallableMemberDescriptor.Kind.FAKE_OVERRIDE }
@@ -465,26 +465,24 @@ class IrOverridingUtil(
val bReturnType = b.returnType val bReturnType = b.returnType
if (!isVisibilityMoreSpecific(a, b)) return false if (!isVisibilityMoreSpecific(a, b)) return false
if (a is IrSimpleFunction) { if (a is IrSimpleFunction) {
assert(b is IrSimpleFunction) { "b is " + b.javaClass } require(b is IrSimpleFunction) { "b is " + b.javaClass }
return isReturnTypeMoreSpecific(a, aReturnType, b, bReturnType) return isReturnTypeMoreSpecific(a, aReturnType, b, bReturnType)
} }
if (a is IrProperty) { if (a is IrProperty) {
assert(b is IrProperty) { "b is " + b.javaClass } require(b is IrProperty) { "b is " + b.javaClass }
val pa = a
val pb = b as IrProperty
if (!isAccessorMoreSpecific( if (!isAccessorMoreSpecific(
pa.setter, a.setter,
pb.setter b.setter
) )
) return false ) return false
return if (pa.isVar && pb.isVar) { return if (a.isVar && b.isVar) {
createTypeCheckerState( createTypeCheckerState(
a.getter!!.typeParameters, a.getter!!.typeParameters,
b.getter!!.typeParameters b.getter!!.typeParameters
).equalTypes(aReturnType, bReturnType) ).equalTypes(aReturnType, bReturnType)
} else { } else {
// both vals or var vs val: val can't be more specific then var // both vals or var vs val: val can't be more specific then var
!(!pa.isVar && pb.isVar) && isReturnTypeMoreSpecific( !(!a.isVar && b.isVar) && isReturnTypeMoreSpecific(
a, aReturnType, a, aReturnType,
b, bReturnType b, bReturnType
) )
@@ -510,7 +508,7 @@ class IrOverridingUtil(
private fun selectMostSpecificMember( private fun selectMostSpecificMember(
overridables: Collection<IrOverridableMember> overridables: Collection<IrOverridableMember>
): IrOverridableMember { ): IrOverridableMember {
assert(!overridables.isEmpty()) { "Should have at least one overridable descriptor" } require(!overridables.isEmpty()) { "Should have at least one overridable descriptor" }
if (overridables.size == 1) { if (overridables.size == 1) {
return overridables.first() return overridables.first()
} }
@@ -693,7 +691,7 @@ class IrOverridingUtil(
} }
*/ */
assert(superValueParameters.size == subValueParameters.size) require(superValueParameters.size == subValueParameters.size)
superValueParameters.forEachIndexed { index, parameter -> superValueParameters.forEachIndexed { index, parameter ->
if (!AbstractTypeChecker.equalTypes( if (!AbstractTypeChecker.equalTypes(
@@ -235,10 +235,9 @@ abstract class DeclarationStubGenerator(
private fun KotlinType.toIrType() = typeTranslator.translateType(this) private fun KotlinType.toIrType() = typeTranslator.translateType(this)
internal fun generateValueParameterStub(descriptor: ValueParameterDescriptor): IrValueParameter = with(descriptor) { internal fun generateValueParameterStub(descriptor: ValueParameterDescriptor): IrValueParameter = with(descriptor) {
symbolTable.irFactory.createValueParameter( IrLazyValueParameter(UNDEFINED_OFFSET, UNDEFINED_OFFSET, computeOrigin(this), IrValueParameterSymbolImpl(this), this, name, index,
UNDEFINED_OFFSET, UNDEFINED_OFFSET, computeOrigin(this), IrValueParameterSymbolImpl(this), name, index, type.toIrType(), type.toIrType(), varargElementType?.toIrType(), isCrossinline, isNoinline, isHidden = false, isAssignable = false, this@DeclarationStubGenerator, typeTranslator)
varargElementType?.toIrType(), isCrossinline, isNoinline, isHidden = false, isAssignable = false .also { irValueParameter ->
).also { irValueParameter ->
if (descriptor.declaresDefaultValue()) { if (descriptor.declaresDefaultValue()) {
irValueParameter.defaultValue = irValueParameter.createStubDefaultValue() irValueParameter.defaultValue = irValueParameter.createStubDefaultValue()
} }
@@ -304,7 +303,7 @@ abstract class DeclarationStubGenerator(
} }
internal fun generateOrGetScopedTypeParameterStub(descriptor: TypeParameterDescriptor): IrTypeParameter { internal fun generateOrGetScopedTypeParameterStub(descriptor: TypeParameterDescriptor): IrTypeParameter {
val referenced = symbolTable.referenceTypeParameter(descriptor) val referenced = symbolTable.referenceScopedTypeParameter(descriptor)
if (referenced.isBound) { if (referenced.isBound) {
return referenced.owner return referenced.owner
} }
@@ -40,6 +40,7 @@ interface ReferenceSymbolTable {
fun referenceValueParameter(descriptor: ParameterDescriptor): IrValueParameterSymbol fun referenceValueParameter(descriptor: ParameterDescriptor): IrValueParameterSymbol
fun referenceTypeParameter(classifier: TypeParameterDescriptor): IrTypeParameterSymbol fun referenceTypeParameter(classifier: TypeParameterDescriptor): IrTypeParameterSymbol
fun referenceScopedTypeParameter(classifier: TypeParameterDescriptor): IrTypeParameterSymbol
fun referenceVariable(descriptor: VariableDescriptor): IrVariableSymbol fun referenceVariable(descriptor: VariableDescriptor): IrVariableSymbol
fun referenceTypeAlias(descriptor: TypeAliasDescriptor): IrTypeAliasSymbol fun referenceTypeAlias(descriptor: TypeAliasDescriptor): IrTypeAliasSymbol
@@ -1030,6 +1031,11 @@ open class SymbolTable(
createTypeParameterSymbol(classifier) createTypeParameterSymbol(classifier)
} }
override fun referenceScopedTypeParameter(classifier: TypeParameterDescriptor): IrTypeParameterSymbol =
scopedTypeParameterSymbolTable.referenced(classifier) {
createTypeParameterSymbol(classifier)
}
override fun referenceGlobalTypeParameterFromLinker(sig: IdSignature): IrTypeParameterSymbol { override fun referenceGlobalTypeParameterFromLinker(sig: IdSignature): IrTypeParameterSymbol {
return globalTypeParameterSymbolTable.referenced(sig, false) { return globalTypeParameterSymbolTable.referenced(sig, false) {
if (sig.isPubliclyVisible) IrTypeParameterPublicSymbolImpl(sig) else IrTypeParameterSymbolImpl() if (sig.isPubliclyVisible) IrTypeParameterPublicSymbolImpl(sig) else IrTypeParameterSymbolImpl()
@@ -35,7 +35,7 @@ abstract class BasicIrModuleDeserializer(
private val moduleDeserializationState = ModuleDeserializationState(linker, this) private val moduleDeserializationState = ModuleDeserializationState(linker, this)
internal val moduleReversedFileIndex = mutableMapOf<IdSignature, FileDeserializationState>() val moduleReversedFileIndex = mutableMapOf<IdSignature, FileDeserializationState>()
override val moduleDependencies by lazy { override val moduleDependencies by lazy {
moduleDescriptor.allDependencyModules.filter { it != moduleDescriptor }.map { linker.resolveModuleDeserializer(it, null) } moduleDescriptor.allDependencyModules.filter { it != moduleDescriptor }.map { linker.resolveModuleDeserializer(it, null) }
@@ -110,6 +110,7 @@ abstract class BasicIrModuleDeserializer(
val fileDeserializationState = FileDeserializationState( val fileDeserializationState = FileDeserializationState(
linker, linker,
fileIndex,
file, file,
fileReader, fileReader,
fileProto, fileProto,
@@ -57,8 +57,9 @@ class IrFileDeserializer(
class FileDeserializationState( class FileDeserializationState(
val linker: KotlinIrLinker, val linker: KotlinIrLinker,
val fileIndex: Int,
file: IrFile, file: IrFile,
fileReader: IrLibraryFileFromBytes, val fileReader: IrLibraryFileFromBytes,
fileProto: ProtoFile, fileProto: ProtoFile,
deserializeBodies: Boolean, deserializeBodies: Boolean,
allowErrorNodes: Boolean, allowErrorNodes: Boolean,
@@ -22,6 +22,7 @@ internal fun IrSymbol.kind(): BinarySymbolData.SymbolKind {
is IrPropertySymbol -> BinarySymbolData.SymbolKind.PROPERTY_SYMBOL is IrPropertySymbol -> BinarySymbolData.SymbolKind.PROPERTY_SYMBOL
is IrEnumEntrySymbol -> BinarySymbolData.SymbolKind.ENUM_ENTRY_SYMBOL is IrEnumEntrySymbol -> BinarySymbolData.SymbolKind.ENUM_ENTRY_SYMBOL
is IrTypeAliasSymbol -> BinarySymbolData.SymbolKind.TYPEALIAS_SYMBOL is IrTypeAliasSymbol -> BinarySymbolData.SymbolKind.TYPEALIAS_SYMBOL
is IrTypeParameterSymbol -> BinarySymbolData.SymbolKind.TYPE_PARAMETER_SYMBOL
else -> error("Unexpected symbol kind $this") else -> error("Unexpected symbol kind $this")
} }
} }
@@ -208,6 +208,7 @@ CLASS IR_EXTERNAL_DECLARATION_STUB CLASS name:Int modality:FINAL visibility:publ
VALUE_PARAMETER IR_EXTERNAL_DECLARATION_STUB name:other index:0 type:kotlin.Int VALUE_PARAMETER IR_EXTERNAL_DECLARATION_STUB name:other index:0 type:kotlin.Int
CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Companion modality:FINAL visibility:public [companion] superTypes:[<unbound IrClassPublicSymbolImpl>] CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Companion modality:FINAL visibility:public [companion] superTypes:[<unbound IrClassPublicSymbolImpl>]
$this: VALUE_PARAMETER IR_EXTERNAL_DECLARATION_STUB name:<this> type:kotlin.Int.Companion $this: VALUE_PARAMETER IR_EXTERNAL_DECLARATION_STUB name:<this> type:kotlin.Int.Companion
CONSTRUCTOR IR_EXTERNAL_DECLARATION_STUB visibility:private <> () returnType:kotlin.Int.Companion [primary]
PROPERTY IR_EXTERNAL_DECLARATION_STUB name:MAX_VALUE visibility:public modality:FINAL [const,val] PROPERTY IR_EXTERNAL_DECLARATION_STUB name:MAX_VALUE visibility:public modality:FINAL [const,val]
FIELD IR_EXTERNAL_DECLARATION_STUB name:MAX_VALUE type:kotlin.Int visibility:public [final] FIELD IR_EXTERNAL_DECLARATION_STUB name:MAX_VALUE type:kotlin.Int visibility:public [final]
EXPRESSION_BODY EXPRESSION_BODY
@@ -364,6 +364,15 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
WorkerExceptionHandling.LEGACY WorkerExceptionHandling.LEGACY
} }
}) })
put(LAZY_IR_FOR_CACHES, when (arguments.lazyIrForCaches) {
null -> true
"enable" -> true
"disable" -> false
else -> {
configuration.report(ERROR, "Expected 'enable' or 'disable' for lazy IR usage for cached libraries")
false
}
})
arguments.externalDependencies?.let { put(EXTERNAL_DEPENDENCIES, it) } arguments.externalDependencies?.let { put(EXTERNAL_DEPENDENCIES, it) }
putIfNotNull(LLVM_VARIANT, when (val variant = arguments.llvmVariant) { putIfNotNull(LLVM_VARIANT, when (val variant = arguments.llvmVariant) {
@@ -361,6 +361,9 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
@Argument(value = "-Xruntime-logs", valueDescription = "<tag1=level1,tag2=level2,...>", description = "Enable logging for runtime with tags.") @Argument(value = "-Xruntime-logs", valueDescription = "<tag1=level1,tag2=level2,...>", description = "Enable logging for runtime with tags.")
var runtimeLogs: String? = null var runtimeLogs: String? = null
@Argument(value = "-Xlazy-ir-for-caches", valueDescription = "{disable|enable}", description = "Use lazy IR for cached libraries")
var lazyIrForCaches: String? = null
override fun configureAnalysisFlags(collector: MessageCollector, languageVersion: LanguageVersion): MutableMap<AnalysisFlag<*>, Any> = override fun configureAnalysisFlags(collector: MessageCollector, languageVersion: LanguageVersion): MutableMap<AnalysisFlag<*>, Any> =
super.configureAnalysisFlags(collector, languageVersion).also { super.configureAnalysisFlags(collector, languageVersion).also {
val optInList = it[AnalysisFlags.optIn] as List<*> val optInList = it[AnalysisFlags.optIn] as List<*>
@@ -53,7 +53,7 @@ internal val Context.getBoxFunction: (IrClass) -> IrSimpleFunction by Context.la
classes.add(parent) classes.add(parent)
parent = parent.parent parent = parent.parent
} }
require(parent is IrFile) { "Local inline classes are not supported" } require(parent is IrFile || parent is IrExternalPackageFragment) { "Local inline classes are not supported" }
val symbols = ir.symbols val symbols = ir.symbols
@@ -100,7 +100,7 @@ internal val Context.getBoxFunction: (IrClass) -> IrSimpleFunction by Context.la
).also { ).also {
it.parent = function it.parent = function
}) })
function.parent = inlinedClass.getContainingFile()!! function.parent = parent
} }
} }
@@ -112,7 +112,7 @@ internal val Context.getUnboxFunction: (IrClass) -> IrSimpleFunction by Context.
classes.add(parent) classes.add(parent)
parent = parent.parent parent = parent.parent
} }
require(parent is IrFile) { "Local inline classes are not supported" } require(parent is IrFile || parent is IrExternalPackageFragment) { "Local inline classes are not supported" }
val symbols = ir.symbols val symbols = ir.symbols
@@ -159,7 +159,7 @@ internal val Context.getUnboxFunction: (IrClass) -> IrSimpleFunction by Context.
).also { ).also {
it.parent = function it.parent = function
}) })
function.parent = inlinedClass.getContainingFile()!! function.parent = parent
} }
} }
@@ -36,11 +36,65 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
internal object DECLARATION_ORIGIN_FUNCTION_CLASS : IrDeclarationOriginImpl("DECLARATION_ORIGIN_FUNCTION_CLASS") internal object DECLARATION_ORIGIN_FUNCTION_CLASS : IrDeclarationOriginImpl("DECLARATION_ORIGIN_FUNCTION_CLASS")
internal class BuiltInFictitiousFunctionIrClassFactory( abstract class KonanIrAbstractDescriptorBasedFunctionFactory : IrProvider, IrAbstractDescriptorBasedFunctionFactory()
var symbolTable: SymbolTable?,
internal class LazyIrFunctionFactory(
private val symbolTable: SymbolTable,
private val stubGenerator: DeclarationStubGenerator,
private val irBuiltIns: IrBuiltInsOverDescriptors, private val irBuiltIns: IrBuiltInsOverDescriptors,
private val reflectionTypes: KonanReflectionTypes private val reflectionTypes: KonanReflectionTypes
) : IrProvider, IrAbstractDescriptorBasedFunctionFactory() { ) : KonanIrAbstractDescriptorBasedFunctionFactory() {
override fun getDeclaration(symbol: IrSymbol) =
(symbol.descriptor as? FunctionClassDescriptor)?.let { descriptor ->
buildClass(descriptor) {
declareClass(descriptor) {
createIrClass(descriptor)
}
}
}
override fun functionClassDescriptor(arity: Int): FunctionClassDescriptor =
irBuiltIns.builtIns.getFunction(arity) as FunctionClassDescriptor
override fun kFunctionClassDescriptor(arity: Int): FunctionClassDescriptor =
reflectionTypes.getKFunction(arity) as FunctionClassDescriptor
override fun suspendFunctionClassDescriptor(arity: Int): FunctionClassDescriptor =
irBuiltIns.builtIns.getSuspendFunction(arity) as FunctionClassDescriptor
override fun kSuspendFunctionClassDescriptor(arity: Int): FunctionClassDescriptor =
reflectionTypes.getKSuspendFunction(arity) as FunctionClassDescriptor
override fun functionN(arity: Int, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass =
buildClass(irBuiltIns.builtIns.getFunction(arity) as FunctionClassDescriptor, declarator)
override fun kFunctionN(arity: Int, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass =
buildClass(reflectionTypes.getKFunction(arity) as FunctionClassDescriptor, declarator)
override fun suspendFunctionN(arity: Int, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass =
buildClass(irBuiltIns.builtIns.getSuspendFunction(arity) as FunctionClassDescriptor, declarator)
override fun kSuspendFunctionN(arity: Int, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass =
buildClass(reflectionTypes.getKSuspendFunction(arity) as FunctionClassDescriptor, declarator)
private val builtClassesMap = mutableMapOf<FunctionClassDescriptor, IrClass>()
private fun createIrClass(descriptor: ClassDescriptor): IrClass =
stubGenerator.generateClassStub(descriptor)
private fun createClass(descriptor: FunctionClassDescriptor, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass =
symbolTable.declarator { createIrClass(descriptor) }
private fun buildClass(descriptor: FunctionClassDescriptor, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass =
builtClassesMap.getOrPut(descriptor) { createClass(descriptor, declarator) }
}
internal class BuiltInFictitiousFunctionIrClassFactory(
private val symbolTable: SymbolTable,
private val irBuiltIns: IrBuiltInsOverDescriptors,
private val reflectionTypes: KonanReflectionTypes
) : KonanIrAbstractDescriptorBasedFunctionFactory() {
override fun getDeclaration(symbol: IrSymbol) = override fun getDeclaration(symbol: IrSymbol) =
(symbol.descriptor as? FunctionClassDescriptor)?.let { descriptor -> (symbol.descriptor as? FunctionClassDescriptor)?.let { descriptor ->
@@ -98,11 +152,11 @@ internal class BuiltInFictitiousFunctionIrClassFactory(
override fun kSuspendFunctionN(arity: Int, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass = override fun kSuspendFunctionN(arity: Int, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass =
buildClass(reflectionTypes.getKSuspendFunction(arity) as FunctionClassDescriptor, declarator) buildClass(reflectionTypes.getKSuspendFunction(arity) as FunctionClassDescriptor, declarator)
private val functionSymbol = symbolTable!!.referenceClass( private val functionSymbol = symbolTable.referenceClass(
irBuiltIns.builtIns.builtInsModule.findClassAcrossModuleDependencies( irBuiltIns.builtIns.builtInsModule.findClassAcrossModuleDependencies(
ClassId.topLevel(KonanFqNames.function))!!) ClassId.topLevel(KonanFqNames.function))!!)
private val kFunctionSymbol = symbolTable!!.referenceClass( private val kFunctionSymbol = symbolTable.referenceClass(
irBuiltIns.builtIns.builtInsModule.findClassAcrossModuleDependencies( irBuiltIns.builtIns.builtInsModule.findClassAcrossModuleDependencies(
ClassId.topLevel(KonanFqNames.kFunction))!!) ClassId.topLevel(KonanFqNames.kFunction))!!)
@@ -121,20 +175,10 @@ internal class BuiltInFictitiousFunctionIrClassFactory(
} }
private fun createTypeParameter(descriptor: TypeParameterDescriptor): IrTypeParameter = private fun createTypeParameter(descriptor: TypeParameterDescriptor): IrTypeParameter =
symbolTable?.declareGlobalTypeParameter( symbolTable.declareGlobalTypeParameter(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, DECLARATION_ORIGIN_FUNCTION_CLASS, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, DECLARATION_ORIGIN_FUNCTION_CLASS,
descriptor descriptor
) )
?: IrTypeParameterImpl(
SYNTHETIC_OFFSET,
SYNTHETIC_OFFSET,
DECLARATION_ORIGIN_FUNCTION_CLASS,
IrTypeParameterSymbolImpl(descriptor),
descriptor.name,
descriptor.index,
descriptor.isReified,
descriptor.variance
)
private fun createSimpleFunction( private fun createSimpleFunction(
descriptor: FunctionDescriptor, descriptor: FunctionDescriptor,
@@ -150,16 +194,14 @@ internal class BuiltInFictitiousFunctionIrClassFactory(
) )
} }
} }
return symbolTable?.declareSimpleFunction(descriptor, functionFactory) return symbolTable.declareSimpleFunction(descriptor, functionFactory)
?: functionFactory(IrSimpleFunctionSymbolImpl(descriptor))
} }
private fun createIrClass(symbol: IrClassSymbol, descriptor: ClassDescriptor): IrClass = private fun createIrClass(symbol: IrClassSymbol, descriptor: ClassDescriptor): IrClass =
IrFactoryImpl.createIrClassFromDescriptor(offset, offset, DECLARATION_ORIGIN_FUNCTION_CLASS, symbol, descriptor) IrFactoryImpl.createIrClassFromDescriptor(offset, offset, DECLARATION_ORIGIN_FUNCTION_CLASS, symbol, descriptor)
private fun createClass(descriptor: FunctionClassDescriptor, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass = private fun createClass(descriptor: FunctionClassDescriptor, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass =
symbolTable?.declarator { createIrClass(it, descriptor) } symbolTable.declarator { createIrClass(it, descriptor) }
?: createIrClass(IrClassSymbolImpl(descriptor), descriptor)
private fun buildClass(descriptor: FunctionClassDescriptor, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass = private fun buildClass(descriptor: FunctionClassDescriptor, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass =
builtClassesMap.getOrPut(descriptor) { builtClassesMap.getOrPut(descriptor) {
@@ -246,8 +288,7 @@ internal class BuiltInFictitiousFunctionIrClassFactory(
private fun toIrType(wrapped: KotlinType): IrType { private fun toIrType(wrapped: KotlinType): IrType {
val kotlinType = wrapped.unwrap() val kotlinType = wrapped.unwrap()
return with(IrSimpleTypeBuilder()) { return with(IrSimpleTypeBuilder()) {
classifier = classifier = symbolTable.referenceClassifier(kotlinType.constructor.declarationDescriptor ?: error("No classifier for type $kotlinType"))
symbolTable?.referenceClassifier(kotlinType.constructor.declarationDescriptor ?: error("No classifier for type $kotlinType"))
hasQuestionMark = kotlinType.isMarkedNullable hasQuestionMark = kotlinType.isMarkedNullable
arguments = kotlinType.arguments.map { arguments = kotlinType.arguments.map {
if (it.isStarProjection) IrStarProjectionImpl if (it.isStarProjection) IrStarProjectionImpl
@@ -296,11 +337,10 @@ internal class BuiltInFictitiousFunctionIrClassFactory(
} }
} }
val newFunction = symbolTable?.declareSimpleFunction(descriptor, functionDeclare) val newFunction = symbolTable.declareSimpleFunction(descriptor, functionDeclare)
?: functionDeclare(IrSimpleFunctionSymbolImpl(descriptor))
newFunction.parent = this newFunction.parent = this
newFunction.overriddenSymbols = descriptor.overriddenDescriptors.mapNotNull { symbolTable?.referenceSimpleFunction(it.original) } newFunction.overriddenSymbols = descriptor.overriddenDescriptors.mapNotNull { symbolTable.referenceSimpleFunction(it.original) }
newFunction.dispatchReceiverParameter = descriptor.dispatchReceiverParameter?.let { newFunction.createValueParameter(it) } newFunction.dispatchReceiverParameter = descriptor.dispatchReceiverParameter?.let { newFunction.createValueParameter(it) }
newFunction.extensionReceiverParameter = descriptor.extensionReceiverParameter?.let { newFunction.createValueParameter(it) } newFunction.extensionReceiverParameter = descriptor.extensionReceiverParameter?.let { newFunction.createValueParameter(it) }
newFunction.valueParameters = descriptor.valueParameters.map { newFunction.createValueParameter(it) } newFunction.valueParameters = descriptor.valueParameters.map { newFunction.createValueParameter(it) }
@@ -327,8 +367,7 @@ internal class BuiltInFictitiousFunctionIrClassFactory(
isExpect = descriptor.isExpect, isExpect = descriptor.isExpect,
isFakeOverride = true) isFakeOverride = true)
} }
val property = symbolTable?.declareProperty(offset, offset, memberOrigin, descriptor, propertyFactory = propertyDeclare) val property = symbolTable.declareProperty(offset, offset, memberOrigin, descriptor, propertyFactory = propertyDeclare)
?: propertyDeclare(IrPropertySymbolImpl(descriptor))
property.parent = this property.parent = this
property.getter = descriptor.getter?.let { g -> createFakeOverrideFunction(g, property.symbol) } property.getter = descriptor.getter?.let { g -> createFakeOverrideFunction(g, property.symbol) }
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.backend.konan package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.backend.konan.serialization.ClassFieldsSerializer
import org.jetbrains.kotlin.backend.konan.serialization.InlineFunctionBodyReferenceSerializer
import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
@@ -25,6 +27,18 @@ class CachedLibraries(
val directory = File(path).absoluteFile.parent val directory = File(path).absoluteFile.parent
File(directory, BITCODE_DEPENDENCIES_FILE_NAME).readStrings() File(directory, BITCODE_DEPENDENCIES_FILE_NAME).readStrings()
} }
val serializedInlineFunctionBodies by lazy {
val directory = File(path).absoluteFile.parent
val data = File(directory, INLINE_FUNCTION_BODIES_FILE_NAME).readBytes()
InlineFunctionBodyReferenceSerializer.deserialize(data)
}
val serializedClassFields by lazy {
val directory = File(path).absoluteFile.parent
val data = File(directory, CLASS_FIELDS_FILE_NAME).readBytes()
ClassFieldsSerializer.deserialize(data)
}
} }
private val cacheDirsContents = mutableMapOf<String, Set<String>>() private val cacheDirsContents = mutableMapOf<String, Set<String>>()
@@ -90,6 +104,9 @@ class CachedLibraries(
companion object { companion object {
fun getCachedLibraryName(library: KotlinLibrary): String = getCachedLibraryName(library.uniqueName) fun getCachedLibraryName(library: KotlinLibrary): String = getCachedLibraryName(library.uniqueName)
fun getCachedLibraryName(libraryName: String): String = "$libraryName-cache" fun getCachedLibraryName(libraryName: String): String = "$libraryName-cache"
const val BITCODE_DEPENDENCIES_FILE_NAME = "bitcode_deps" const val BITCODE_DEPENDENCIES_FILE_NAME = "bitcode_deps"
const val INLINE_FUNCTION_BODIES_FILE_NAME = "inline_bodies"
const val CLASS_FIELDS_FILE_NAME = "class_fields"
} }
} }
@@ -42,6 +42,9 @@ import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.copyToWithoutSuperTypes import org.jetbrains.kotlin.backend.common.ir.copyToWithoutSuperTypes
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
import org.jetbrains.kotlin.backend.konan.llvm.coverage.CoverageManager import org.jetbrains.kotlin.backend.konan.llvm.coverage.CoverageManager
import org.jetbrains.kotlin.backend.konan.serialization.KonanIrLinker
import org.jetbrains.kotlin.backend.konan.serialization.SerializedClassFields
import org.jetbrains.kotlin.backend.konan.serialization.SerializedInlineFunctionReference
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyClass import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyClass
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
@@ -51,6 +54,8 @@ import org.jetbrains.kotlin.konan.util.disposeNativeMemoryAllocator
import org.jetbrains.kotlin.library.SerializedIrModule import org.jetbrains.kotlin.library.SerializedIrModule
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
internal class InlineFunctionOriginInfo(val irFile: IrFile, val startOffset: Int, val endOffset: Int)
/** /**
* Offset for synthetic elements created by lowerings and not attributable to other places in the source code. * Offset for synthetic elements created by lowerings and not attributable to other places in the source code.
*/ */
@@ -65,7 +70,7 @@ internal class SpecialDeclarationsFactory(val context: Context) {
private val bridges = mutableMapOf<BridgeKey, IrSimpleFunction>() private val bridges = mutableMapOf<BridgeKey, IrSimpleFunction>()
val loweredInlineFunctions = mutableSetOf<IrFunction>() val loweredInlineFunctions = mutableMapOf<IrFunction, InlineFunctionOriginInfo>()
object DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS : object DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS :
IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS") IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS")
@@ -494,6 +499,12 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
* Manages internal ABI references and declarations. * Manages internal ABI references and declarations.
*/ */
val internalAbi = InternalAbi(this) val internalAbi = InternalAbi(this)
lateinit var irLinker: KonanIrLinker
val inlineFunctionBodies = mutableListOf<SerializedInlineFunctionReference>()
val classFields = mutableListOf<SerializedClassFields>()
} }
private fun MemberScope.getContributedClassifier(name: String) = private fun MemberScope.getContributedClassifier(name: String) =
@@ -19,14 +19,24 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrTryImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.SYNTHETIC_OFFSET
import org.jetbrains.kotlin.ir.util.irCatch import org.jetbrains.kotlin.ir.util.irCatch
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
internal fun makeEntryPoint(context: Context): IrFunction { internal fun makeEntryPoint(context: Context): IrFunction {
val actualMain = context.ir.symbols.entryPoint!!.owner val actualMain = context.ir.symbols.entryPoint!!.owner
// TODO: Do we need to do something with the offsets if <main> is in a cached library?
val startOffset = if (context.llvmModuleSpecification.containsDeclaration(actualMain))
actualMain.startOffset
else
SYNTHETIC_OFFSET
val endOffset = if (context.llvmModuleSpecification.containsDeclaration(actualMain))
actualMain.endOffset
else
SYNTHETIC_OFFSET
val entryPoint = IrFunctionImpl( val entryPoint = IrFunctionImpl(
actualMain.startOffset, startOffset,
actualMain.startOffset, endOffset,
IrDeclarationOrigin.DEFINED, IrDeclarationOrigin.DEFINED,
IrSimpleFunctionSymbolImpl(), IrSimpleFunctionSymbolImpl(),
Name.identifier("Konan_start"), Name.identifier("Konan_start"),
@@ -44,7 +54,7 @@ internal fun makeEntryPoint(context: Context): IrFunction {
).also { function -> ).also { function ->
function.valueParameters = listOf( function.valueParameters = listOf(
IrValueParameterImpl( IrValueParameterImpl(
actualMain.startOffset, actualMain.startOffset, startOffset, endOffset,
IrDeclarationOrigin.DEFINED, IrDeclarationOrigin.DEFINED,
IrValueParameterSymbolImpl(), IrValueParameterSymbolImpl(),
Name.identifier("args"), Name.identifier("args"),
@@ -60,16 +70,12 @@ internal fun makeEntryPoint(context: Context): IrFunction {
}) })
} }
entryPoint.annotations += buildSimpleAnnotation(context.irBuiltIns, entryPoint.annotations += buildSimpleAnnotation(context.irBuiltIns,
actualMain.startOffset, actualMain.startOffset, startOffset, endOffset,
context.ir.symbols.exportForCppRuntime.owner, "Konan_start") context.ir.symbols.exportForCppRuntime.owner, "Konan_start")
val builder = context.createIrBuilder(entryPoint.symbol) val builder = context.createIrBuilder(entryPoint.symbol)
entryPoint.body = builder.irBlockBody(entryPoint) { entryPoint.body = builder.irBlockBody(entryPoint) {
+IrTryImpl( +IrTryImpl(startOffset, endOffset, context.irBuiltIns.nothingType).apply {
startOffset = actualMain.startOffset,
endOffset = actualMain.startOffset,
type = context.irBuiltIns.nothingType
).apply {
tryResult = irBlock { tryResult = irBlock {
+irCall(actualMain).apply { +irCall(actualMain).apply {
if (actualMain.valueParameters.size != 0) if (actualMain.valueParameters.size != 0)
@@ -273,6 +273,8 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
internal val isInteropStubs: Boolean get() = manifestProperties?.getProperty("interop") == "true" internal val isInteropStubs: Boolean get() = manifestProperties?.getProperty("interop") == "true"
internal val propertyLazyInitialization: Boolean get() = configuration.get(KonanConfigKeys.PROPERTY_LAZY_INITIALIZATION)!! internal val propertyLazyInitialization: Boolean get() = configuration.get(KonanConfigKeys.PROPERTY_LAZY_INITIALIZATION)!!
internal val lazyIrForCaches: Boolean get() = configuration.get(KonanConfigKeys.LAZY_IR_FOR_CACHES)!!
} }
fun CompilerConfiguration.report(priority: CompilerMessageSeverity, message: String) fun CompilerConfiguration.report(priority: CompilerMessageSeverity, message: String)
@@ -170,6 +170,7 @@ class KonanConfigKeys {
CompilerConfigurationKey.create("use external dependencies to enhance IR linker error messages") CompilerConfigurationKey.create("use external dependencies to enhance IR linker error messages")
val LLVM_VARIANT: CompilerConfigurationKey<LlvmVariant?> = CompilerConfigurationKey.create("llvm variant") val LLVM_VARIANT: CompilerConfigurationKey<LlvmVariant?> = CompilerConfigurationKey.create("llvm variant")
val RUNTIME_LOGS: CompilerConfigurationKey<String> = CompilerConfigurationKey.create("enable runtime logging") val RUNTIME_LOGS: CompilerConfigurationKey<String> = CompilerConfigurationKey.create("enable runtime logging")
val LAZY_IR_FOR_CACHES: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create("use lazy IR for cached libraries")
} }
} }
@@ -1,5 +1,7 @@
package org.jetbrains.kotlin.backend.konan package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.backend.konan.serialization.ClassFieldsSerializer
import org.jetbrains.kotlin.backend.konan.serialization.InlineFunctionBodyReferenceSerializer
import org.jetbrains.kotlin.konan.KonanExternalToolFailure import org.jetbrains.kotlin.konan.KonanExternalToolFailure
import org.jetbrains.kotlin.konan.exec.Command import org.jetbrains.kotlin.konan.exec.Command
import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.konan.file.File
@@ -58,6 +60,8 @@ internal class Linker(val context: Context) {
private fun saveAdditionalInfoForCache() { private fun saveAdditionalInfoForCache() {
saveCacheBitcodeDependencies() saveCacheBitcodeDependencies()
saveInlineFunctionBodies()
saveClassFields()
} }
private fun saveCacheBitcodeDependencies() { private fun saveCacheBitcodeDependencies() {
@@ -73,6 +77,18 @@ internal class Linker(val context: Context) {
bitcodeDependenciesFile.writeLines(bitcodeDependencies.map { it.uniqueName }) bitcodeDependenciesFile.writeLines(bitcodeDependencies.map { it.uniqueName })
} }
private fun saveInlineFunctionBodies() {
val outputFiles = context.config.outputFiles
val inlineFunctionBodiesFile = File(outputFiles.inlineFunctionBodiesFile!!)
inlineFunctionBodiesFile.writeBytes(InlineFunctionBodyReferenceSerializer.serialize(context.inlineFunctionBodies))
}
private fun saveClassFields() {
val outputFiles = context.config.outputFiles
val classFieldsFile = File(outputFiles.classFieldsFile!!)
classFieldsFile.writeBytes(ClassFieldsSerializer.serialize(context.classFields))
}
private fun renameOutput() { private fun renameOutput() {
if (context.config.produce.isCache) { if (context.config.produce.isCache) {
val outputFiles = context.config.outputFiles val outputFiles = context.config.outputFiles
@@ -63,6 +63,16 @@ class OutputFiles(outputPath: String?, target: KonanTarget, val produce: Compile
tempCacheDirectory!!.child(CachedLibraries.BITCODE_DEPENDENCIES_FILE_NAME).absolutePath tempCacheDirectory!!.child(CachedLibraries.BITCODE_DEPENDENCIES_FILE_NAME).absolutePath
else null else null
val inlineFunctionBodiesFile =
if (produce.isCache)
tempCacheDirectory!!.child(CachedLibraries.INLINE_FUNCTION_BODIES_FILE_NAME).absolutePath
else null
val classFieldsFile =
if (produce.isCache)
tempCacheDirectory!!.child(CachedLibraries.CLASS_FIELDS_FILE_NAME).absolutePath
else null
private fun String.fullOutputName() = prefixBaseNameIfNeeded(prefix).suffixIfNeeded(suffix) private fun String.fullOutputName() = prefixBaseNameIfNeeded(prefix).suffixIfNeeded(suffix)
private fun String.prefixBaseNameIfNeeded(prefix: String) = private fun String.prefixBaseNameIfNeeded(prefix: String) =
@@ -53,15 +53,17 @@ internal fun Context.psiToIr(
// Note: using [llvmModuleSpecification] since this phase produces IR for generating single LLVM module. // Note: using [llvmModuleSpecification] since this phase produces IR for generating single LLVM module.
val exportedDependencies = (getExportedDependencies() + modulesWithoutDCE).distinct()
val irBuiltInsOverDescriptors = generatorContext.irBuiltIns as IrBuiltInsOverDescriptors
val functionIrClassFactory = BuiltInFictitiousFunctionIrClassFactory(
symbolTable, irBuiltInsOverDescriptors, reflectionTypes)
irBuiltInsOverDescriptors.functionFactory = functionIrClassFactory
val stubGenerator = DeclarationStubGeneratorImpl( val stubGenerator = DeclarationStubGeneratorImpl(
moduleDescriptor, symbolTable, moduleDescriptor, symbolTable,
generatorContext.irBuiltIns generatorContext.irBuiltIns
) )
val irBuiltInsOverDescriptors = generatorContext.irBuiltIns as IrBuiltInsOverDescriptors
val functionIrClassFactory: KonanIrAbstractDescriptorBasedFunctionFactory =
if (config.lazyIrForCaches && !llvmModuleSpecification.containsModule(this.stdlibModule))
LazyIrFunctionFactory(symbolTable, stubGenerator, irBuiltInsOverDescriptors, reflectionTypes)
else
BuiltInFictitiousFunctionIrClassFactory(symbolTable, irBuiltInsOverDescriptors, reflectionTypes)
irBuiltInsOverDescriptors.functionFactory = functionIrClassFactory
val symbols = KonanSymbols(this, generatorContext.irBuiltIns, symbolTable, symbolTable.lazyWrapper) val symbols = KonanSymbols(this, generatorContext.irBuiltIns, symbolTable, symbolTable.lazyWrapper)
val irDeserializer = if (isProducingLibrary && !useLinkerWhenProducingLibrary) { val irDeserializer = if (isProducingLibrary && !useLinkerWhenProducingLibrary) {
@@ -77,6 +79,7 @@ internal fun Context.psiToIr(
} }
} }
} else { } else {
val exportedDependencies = (getExportedDependencies() + modulesWithoutDCE).distinct()
val irProviderForCEnumsAndCStructs = val irProviderForCEnumsAndCStructs =
IrProviderForCEnumAndCStructStubs(generatorContext, interopBuiltIns, symbols) IrProviderForCEnumAndCStructStubs(generatorContext, interopBuiltIns, symbols)
@@ -102,6 +105,7 @@ internal fun Context.psiToIr(
irProviderForCEnumsAndCStructs, irProviderForCEnumsAndCStructs,
exportedDependencies, exportedDependencies,
config.cachedLibraries, config.cachedLibraries,
config.lazyIrForCaches,
config.userVisibleIrModulesSupport config.userVisibleIrModulesSupport
).also { linker -> ).also { linker ->
@@ -120,15 +124,14 @@ internal fun Context.psiToIr(
} }
for (dependency in sortDependencies(dependencies).filter { it != moduleDescriptor }) { for (dependency in sortDependencies(dependencies).filter { it != moduleDescriptor }) {
val kotlinLibrary = dependency.getCapability(KlibModuleOrigin.CAPABILITY)?.let { val kotlinLibrary = (dependency.getCapability(KlibModuleOrigin.CAPABILITY) as? DeserializedKlibModuleOrigin)?.library
(it as? DeserializedKlibModuleOrigin)?.library val isCachedLibrary = kotlinLibrary != null && config.cachedLibraries.isLibraryCached(kotlinLibrary)
} if (isProducingLibrary || (config.lazyIrForCaches && isCachedLibrary))
when { linker.deserializeOnlyHeaderModule(dependency, kotlinLibrary)
isProducingLibrary -> linker.deserializeOnlyHeaderModule(dependency, kotlinLibrary) else if (isCachedLibrary)
kotlinLibrary != null && config.cachedLibraries.isLibraryCached(kotlinLibrary) -> linker.deserializeHeadersWithInlineBodies(dependency, kotlinLibrary!!)
linker.deserializeHeadersWithInlineBodies(dependency, kotlinLibrary) else
else -> linker.deserializeIrModuleHeader(dependency, kotlinLibrary, dependency.name.asString()) linker.deserializeIrModuleHeader(dependency, kotlinLibrary, dependency.name.asString())
}
} }
if (dependencies.size == dependenciesCount) break if (dependencies.size == dependenciesCount) break
dependenciesCount = dependencies.size dependenciesCount = dependencies.size
@@ -140,7 +143,6 @@ internal fun Context.psiToIr(
.filter(ModuleDescriptor::isFromInteropLibrary) .filter(ModuleDescriptor::isFromInteropLibrary)
.forEach(irProviderForCEnumsAndCStructs::referenceAllEnumsAndStructsFrom) .forEach(irProviderForCEnumsAndCStructs::referenceAllEnumsAndStructsFrom)
translator.addPostprocessingStep { translator.addPostprocessingStep {
irProviderForCEnumsAndCStructs.generateBodies() irProviderForCEnumsAndCStructs.generateBodies()
} }
@@ -197,14 +199,19 @@ internal fun Context.psiToIr(
// Note: coupled with [shouldLower] below. // Note: coupled with [shouldLower] below.
irModules = modules.filterValues { llvmModuleSpecification.containsModule(it) } irModules = modules.filterValues { llvmModuleSpecification.containsModule(it) }
if (!isProducingLibrary)
irLinker = irDeserializer as KonanIrLinker
ir.symbols = symbols ir.symbols = symbols
if (!isProducingLibrary) { if (!isProducingLibrary) {
// TODO: find out what should be done in the new builtins/symbols about it // TODO: find out what should be done in the new builtins/symbols about it
if (this.stdlibModule in modulesWithoutDCE) if (this.stdlibModule in modulesWithoutDCE) {
functionIrClassFactory.buildAllClasses() (functionIrClassFactory as BuiltInFictitiousFunctionIrClassFactory).buildAllClasses()
}
internalAbi.init(irModules.values + irModule!!) internalAbi.init(irModules.values + irModule!!)
functionIrClassFactory.module = (modules.values + irModule!!).single { it.descriptor.isNativeStdlib() } (functionIrClassFactory as? BuiltInFictitiousFunctionIrClassFactory)?.module =
(modules.values + irModule!!).single { it.descriptor.isNativeStdlib() }
} }
mainModule.files.forEach { it.metadata = KonanFileMetadataSource(mainModule) } mainModule.files.forEach { it.metadata = KonanFileMetadataSource(mainModule) }
@@ -7,13 +7,12 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.phaser.* import org.jetbrains.kotlin.backend.common.phaser.*
import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMonolithicSerializer import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMonolithicSerializer
import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary
import org.jetbrains.kotlin.backend.konan.llvm.* import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier
import org.jetbrains.kotlin.backend.konan.lower.SamSuperTypesChecker import org.jetbrains.kotlin.backend.konan.lower.SamSuperTypesChecker
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
import org.jetbrains.kotlin.backend.konan.serialization.KonanIdSignaturer import org.jetbrains.kotlin.backend.konan.serialization.*
import org.jetbrains.kotlin.backend.konan.serialization.KonanIrModuleSerializer
import org.jetbrains.kotlin.backend.konan.serialization.KonanManglerDesc
import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
@@ -32,6 +31,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.name.FqName
internal fun moduleValidationCallback(state: ActionState, module: IrModuleFragment, context: Context) { internal fun moduleValidationCallback(state: ActionState, module: IrModuleFragment, context: Context) {
if (!context.config.needVerifyIr) return if (!context.config.needVerifyIr) return
@@ -124,6 +124,47 @@ internal val psiToIrPhase = konanUnitPhase(
prerequisite = setOf(createSymbolTablePhase) prerequisite = setOf(createSymbolTablePhase)
) )
internal val buildAdditionalCacheInfoPhase = konanUnitPhase(
op = {
irModules.values.single().let { module ->
val moduleDeserializer = irLinker.nonCachedLibraryModuleDeserializers[module.descriptor]
if (moduleDeserializer == null) {
require(module.descriptor.isFromInteropLibrary()) { "No module deserializer for ${module.descriptor}" }
} else {
val compatibleMode = CompatibilityMode(moduleDeserializer.libraryAbiVersion).oldSignatures
module.acceptChildrenVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitClass(declaration: IrClass) {
declaration.acceptChildrenVoid(this)
if (declaration.isExported && declaration.origin != DECLARATION_ORIGIN_FUNCTION_CLASS)
classFields.add(moduleDeserializer.buildClassFields(declaration, getLayoutBuilder(declaration).getDeclaredFields()))
}
override fun visitFunction(declaration: IrFunction) {
declaration.acceptChildrenVoid(this)
if (declaration.isFakeOverride || !declaration.isExportedInlineFunction) return
inlineFunctionBodies.add(moduleDeserializer.buildInlineFunctionReference(declaration))
}
private val IrClass.isExported
get() = with(KonanManglerIr) { isExported(compatibleMode) }
private val IrFunction.isExportedInlineFunction
get() = isInline && with(KonanManglerIr) { isExported(compatibleMode) }
})
}
}
},
name = "BuildAdditionalCacheInfo",
description = "Build additional cache info (inline functions bodies and fields of classes)",
prerequisite = setOf(psiToIrPhase)
)
// Coupled with [psiToIrPhase] logic above. // Coupled with [psiToIrPhase] logic above.
internal fun shouldLower(context: Context, declaration: IrDeclaration): Boolean { internal fun shouldLower(context: Context, declaration: IrDeclaration): Boolean {
return context.llvmModuleSpecification.containsDeclaration(declaration) return context.llvmModuleSpecification.containsDeclaration(declaration)
@@ -305,21 +346,17 @@ internal val entryPointPhase = makeCustomPhase<Context, IrModuleFragment>(
description = "Add entry point for program", description = "Add entry point for program",
prerequisite = emptySet(), prerequisite = emptySet(),
op = { context, _ -> op = { context, _ ->
assert(context.config.produce == CompilerOutputKind.PROGRAM) require(context.config.produce == CompilerOutputKind.PROGRAM)
val originalFile = context.ir.symbols.entryPoint!!.owner.file val entryPoint = context.ir.symbols.entryPoint!!.owner
val originalModule = originalFile.packageFragmentDescriptor.containingDeclaration val file = if (context.llvmModuleSpecification.containsDeclaration(entryPoint)) {
val file = if (context.llvmModuleSpecification.containsModule(originalModule)) { entryPoint.file
originalFile
} else { } else {
// `main` function is compiled to other LLVM module. // `main` function is compiled to other LLVM module.
// For example, test running support uses `main` defined in stdlib. // For example, test running support uses `main` defined in stdlib.
context.irModule!!.addFile(originalFile.fileEntry, originalFile.fqName) context.irModule!!.addFile(NaiveSourceBasedFileEntryImpl("entryPointOwner"), FqName("kotlin.native.caches.abi"))
} }
require(context.llvmModuleSpecification.containsModule(
file.packageFragmentDescriptor.containingDeclaration))
file.addChild(makeEntryPoint(context)) file.addChild(makeEntryPoint(context))
} }
) )
@@ -444,6 +481,7 @@ val toplevelPhase: CompilerPhase<*, Unit, Unit> = namedUnitPhase(
objCExportPhase then objCExportPhase then
buildCExportsPhase then buildCExportsPhase then
psiToIrPhase then psiToIrPhase then
buildAdditionalCacheInfoPhase then
destroySymbolTablePhase then destroySymbolTablePhase then
copyDefaultValuesToActualPhase then copyDefaultValuesToActualPhase then
checkSamSuperTypesPhase then checkSamSuperTypesPhase then
@@ -478,6 +516,7 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
// Don't serialize anything to a final executable. // Don't serialize anything to a final executable.
disableUnless(serializerPhase, config.produce == CompilerOutputKind.LIBRARY) disableUnless(serializerPhase, config.produce == CompilerOutputKind.LIBRARY)
disableUnless(entryPointPhase, config.produce == CompilerOutputKind.PROGRAM) disableUnless(entryPointPhase, config.produce == CompilerOutputKind.PROGRAM)
disableUnless(buildAdditionalCacheInfoPhase, config.produce.isCache)
disableUnless(exportInternalAbiPhase, config.produce.isCache) disableUnless(exportInternalAbiPhase, config.produce.isCache)
disableIf(backendCodegen, config.produce == CompilerOutputKind.LIBRARY) disableIf(backendCodegen, config.produce == CompilerOutputKind.LIBRARY)
disableUnless(bitcodeOptimizationPhase, config.produce.involvesLinkStage) disableUnless(bitcodeOptimizationPhase, config.produce.involvesLinkStage)
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.library.isInterop
internal class OverriddenFunctionInfo( internal class OverriddenFunctionInfo(
val function: IrSimpleFunction, val function: IrSimpleFunction,
@@ -466,6 +467,19 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context, va
* Fields declared in the class. * Fields declared in the class.
*/ */
fun getDeclaredFields(): List<FieldInfo> { fun getDeclaredFields(): List<FieldInfo> {
if (context.config.lazyIrForCaches && !context.llvmModuleSpecification.containsDeclaration(irClass)) {
val packageFragment = irClass.findPackage()
val moduleDescriptor = packageFragment.packageFragmentDescriptor.containingDeclaration
if (moduleDescriptor.isFromInteropLibrary())
return emptyList()
val moduleDeserializer = context.irLinker.cachedLibraryModuleDeserializers[moduleDescriptor]
?: error("No module deserializer for ${irClass.render()}")
val fields = moduleDeserializer.deserializeClassFields(irClass).toMutableList()
if (irClass.isInner)
fields.add(InnerClassLowering.addOuterThisField(mutableListOf(), irClass, context).toFieldInfo())
return fields
}
val declarations: List<IrDeclaration> = if (irClass.isInner && !isLowered) { val declarations: List<IrDeclaration> = if (irClass.isInner && !isLowered) {
// Note: copying to avoid mutation of the original class. // Note: copying to avoid mutation of the original class.
irClass.declarations.toMutableList() irClass.declarations.toMutableList()
@@ -6,20 +6,16 @@
package org.jetbrains.kotlin.backend.konan.ir package org.jetbrains.kotlin.backend.konan.ir
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.findPackage
import org.jetbrains.kotlin.backend.konan.llvm.llvmSymbolOrigin import org.jetbrains.kotlin.backend.konan.llvm.llvmSymbolOrigin
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyDeclarationBase
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.file
// This file contains some IR utilities which actually use descriptors. // This file contains some IR utilities which actually use descriptors.
// TODO: port this code to IR. // TODO: port this code to IR.
internal val IrDeclaration.llvmSymbolOrigin get() = when (this) { internal val IrDeclaration.llvmSymbolOrigin get() = findPackage().packageFragmentDescriptor.llvmSymbolOrigin
is IrLazyDeclarationBase -> descriptor.llvmSymbolOrigin
else -> file.packageFragmentDescriptor.llvmSymbolOrigin
}
internal fun IrType.isObjCObjectType() = this.toKotlinType().isObjCObjectType() internal fun IrType.isObjCObjectType() = this.toKotlinType().isObjCObjectType()
@@ -1824,15 +1824,23 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private inner class ReturnableBlockScope(val returnableBlock: IrReturnableBlock) : private inner class ReturnableBlockScope(val returnableBlock: IrReturnableBlock) :
FileScope(returnableBlock.sourceFileSymbol?.owner ?: (currentCodeContext.fileScope() as? FileScope)?.file ?: error("returnable block should belong to current file at least") ) { FileScope(returnableBlock.inlineFunctionSymbol?.owner?.let {
context.specialDeclarationsFactory.loweredInlineFunctions[it]?.irFile ?: it.fileOrNull
}
?: (currentCodeContext.fileScope() as? FileScope)?.file
?: error("returnable block should belong to current file at least")) {
var bbExit : LLVMBasicBlockRef? = null var bbExit : LLVMBasicBlockRef? = null
var resultPhi : LLVMValueRef? = null var resultPhi : LLVMValueRef? = null
private val functionScope by lazy { returnableBlock.inlineFunctionSymbol?.owner?.scope() } private val functionScope by lazy {
returnableBlock.inlineFunctionSymbol?.owner?.let {
it.scope(file().fileEntry.line(context.specialDeclarationsFactory.loweredInlineFunctions[it]?.startOffset ?: it.startOffset))
}
}
private fun getExit(): LLVMBasicBlockRef { private fun getExit(): LLVMBasicBlockRef {
val location = returnableBlock.inlineFunctionSymbol?.let { val location = returnableBlock.inlineFunctionSymbol?.owner?.let {
location(it.owner.endOffset) location(context.specialDeclarationsFactory.loweredInlineFunctions[it]?.endOffset ?: it.endOffset)
} ?: returnableBlock.statements.lastOrNull()?.let { } ?: returnableBlock.statements.lastOrNull()?.let {
location(it.endOffset) location(it.endOffset)
} }
@@ -12,25 +12,38 @@ import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesExtractionFr
import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesInInlineFunctionsLowering import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesInInlineFunctionsLowering
import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesInInlineLambdasLowering import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesInInlineLambdasLowering
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.InlineFunctionOriginInfo
import org.jetbrains.kotlin.backend.konan.descriptors.findPackage
import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.util.dump import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.file import org.jetbrains.kotlin.ir.util.file
import org.jetbrains.kotlin.ir.util.fileOrNull import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.util.getPackageFragment
// TODO: This is a bit hacky. Think about adopting persistent IR ideas. // TODO: This is a bit hacky. Think about adopting persistent IR ideas.
internal class NativeInlineFunctionResolver(override val context: Context) : DefaultInlineFunctionResolver(context) { internal class NativeInlineFunctionResolver(override val context: Context) : DefaultInlineFunctionResolver(context) {
override fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction { override fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction {
val function = super.getFunctionDeclaration(symbol) val function = super.getFunctionDeclaration(symbol)
val body = function.body ?: return function
if (function in context.specialDeclarationsFactory.loweredInlineFunctions) if (function in context.specialDeclarationsFactory.loweredInlineFunctions)
return function return function
context.specialDeclarationsFactory.loweredInlineFunctions.add(function) val packageFragment = function.findPackage()
if (packageFragment !is IrExternalPackageFragment) {
context.specialDeclarationsFactory.loweredInlineFunctions[function] =
InlineFunctionOriginInfo(function.file, function.startOffset, function.endOffset)
} else {
// The function is from Lazy IR, get its body from the IR linker.
val moduleDescriptor = packageFragment.packageFragmentDescriptor.containingDeclaration
val moduleDeserializer = context.irLinker.cachedLibraryModuleDeserializers[moduleDescriptor]
?: error("No module deserializer for ${function.render()}")
context.specialDeclarationsFactory.loweredInlineFunctions[function] = moduleDeserializer.deserializeInlineFunction(function)
}
PreInlineLowering(context).lower(body, function) val body = function.body ?: return function
PreInlineLowering(context).lower(body, function, context.specialDeclarationsFactory.loweredInlineFunctions[function]!!.irFile)
ArrayConstructorLowering(context).lower(body, function) ArrayConstructorLowering(context).lower(body, function)
@@ -44,7 +57,7 @@ internal class NativeInlineFunctionResolver(override val context: Context) : Def
LocalClassesInInlineLambdasLowering(context).lower(body, function) LocalClassesInInlineLambdasLowering(context).lower(body, function)
if (context.llvmModuleSpecification.containsPackageFragment(function.getPackageFragment()!!)) { if (context.llvmModuleSpecification.containsPackageFragment(packageFragment)) {
// Do not extract local classes off of inline functions from cached libraries. // Do not extract local classes off of inline functions from cached libraries.
LocalClassesInInlineFunctionsLowering(context).lower(body, function) LocalClassesInInlineFunctionsLowering(context).lower(body, function)
LocalClassesExtractionFromInlineFunctionsLowering(context).lower(body, function) LocalClassesExtractionFromInlineFunctionsLowering(context).lower(body, function)
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
import org.jetbrains.kotlin.ir.expressions.IrBody import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
@@ -35,7 +36,9 @@ internal class PreInlineLowering(val context: Context) : BodyLoweringPass {
private val asserts = symbols.asserts private val asserts = symbols.asserts
private val enableAssertions = context.config.configuration.getBoolean(KonanConfigKeys.ENABLE_ASSERTIONS) private val enableAssertions = context.config.configuration.getBoolean(KonanConfigKeys.ENABLE_ASSERTIONS)
override fun lower(irBody: IrBody, container: IrDeclaration) { override fun lower(irBody: IrBody, container: IrDeclaration) = lower(irBody, container, container.file)
fun lower(irBody: IrBody, container: IrDeclaration, irFile: IrFile) {
irBody.transformChildren(object : IrElementTransformer<IrBuilderWithScope> { irBody.transformChildren(object : IrElementTransformer<IrBuilderWithScope> {
override fun visitDeclaration(declaration: IrDeclarationBase, data: IrBuilderWithScope) = override fun visitDeclaration(declaration: IrDeclarationBase, data: IrBuilderWithScope) =
super.visitDeclaration(declaration, super.visitDeclaration(declaration,
@@ -53,7 +56,7 @@ internal class PreInlineLowering(val context: Context) : BodyLoweringPass {
IrCompositeImpl(expression.startOffset, expression.endOffset, expression.type) IrCompositeImpl(expression.startOffset, expression.endOffset, expression.type)
} }
Symbols.isTypeOfIntrinsic(expression.symbol) -> { Symbols.isTypeOfIntrinsic(expression.symbol) -> {
with (KTypeGenerator(context, container.file, expression, needExactTypeParameters = true)) { with (KTypeGenerator(context, irFile, expression, needExactTypeParameters = true)) {
data.at(expression).irKType(expression.getTypeArgument(0)!!, leaveReifiedForLater = true) data.at(expression).irKType(expression.getTypeArgument(0)!!, leaveReifiedForLater = true)
} }
} }
@@ -16,12 +16,20 @@
package org.jetbrains.kotlin.backend.konan.serialization package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.common.lower.parents
import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideBuilder import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideBuilder
import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideClassFilter import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideClassFilter
import org.jetbrains.kotlin.backend.common.overrides.FileLocalAwareLinker
import org.jetbrains.kotlin.backend.common.serialization.* import org.jetbrains.kotlin.backend.common.serialization.*
import org.jetbrains.kotlin.backend.common.serialization.encodings.BinaryNameAndType
import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData
import org.jetbrains.kotlin.backend.common.serialization.linkerissues.UserVisibleIrModulesSupport import org.jetbrains.kotlin.backend.common.serialization.linkerissues.UserVisibleIrModulesSupport
import org.jetbrains.kotlin.backend.konan.CachedLibraries import org.jetbrains.kotlin.backend.konan.CachedLibraries
import org.jetbrains.kotlin.backend.common.serialization.encodings.FunctionFlags
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.InlineFunctionOriginInfo
import org.jetbrains.kotlin.backend.konan.descriptors.ClassLayoutBuilder
import org.jetbrains.kotlin.backend.konan.descriptors.findPackage
import org.jetbrains.kotlin.backend.konan.descriptors.isInteropLibrary import org.jetbrains.kotlin.backend.konan.descriptors.isInteropLibrary
import org.jetbrains.kotlin.backend.konan.ir.interop.IrProviderForCEnumAndCStructStubs import org.jetbrains.kotlin.backend.konan.ir.interop.IrProviderForCEnumAndCStructStubs
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
@@ -31,11 +39,17 @@ import org.jetbrains.kotlin.descriptors.konan.klibModuleOrigin
import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.builders.TranslationPluginContext import org.jetbrains.kotlin.ir.builders.TranslationPluginContext
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyClass
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrPublicSymbolBase import org.jetbrains.kotlin.ir.symbols.impl.IrPublicSymbolBase
import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl
import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.defaultType
import org.jetbrains.kotlin.ir.types.getPublicSignature
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
@@ -44,7 +58,237 @@ import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.backend.common.serialization.proto.IrFile as ProtoFile
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDeclaration as ProtoDeclaration
import org.jetbrains.kotlin.backend.common.serialization.proto.IrClass as ProtoClass
import org.jetbrains.kotlin.backend.common.serialization.proto.IrFunction as ProtoFunction
import org.jetbrains.kotlin.backend.common.serialization.proto.IrProperty as ProtoProperty
import org.jetbrains.kotlin.backend.common.serialization.proto.IrField as ProtoField
import sun.misc.Unsafe
private val unsafe = with(Unsafe::class.java.getDeclaredField("theUnsafe")) {
isAccessible = true
return@with this.get(null) as Unsafe
}
private val byteArrayBaseOffset = unsafe.arrayBaseOffset(ByteArray::class.java).toLong()
internal class ByteArrayStream(val buf: ByteArray) {
private var offset = 0
fun hasData() = offset < buf.size
fun readInt(): Int {
checkSize(offset + Int.SIZE_BYTES) { "Can't read an int at $offset, size = ${buf.size}" }
return unsafe.getInt(buf, byteArrayBaseOffset + offset).also { offset += Int.SIZE_BYTES }
}
fun writeInt(value: Int) {
checkSize(offset + Int.SIZE_BYTES) { "Can't write an int at $offset, size = ${buf.size}" }
unsafe.putInt(buf, byteArrayBaseOffset + offset, value).also { offset += Int.SIZE_BYTES }
}
private fun checkSize(at: Int, messageBuilder: () -> String) {
if (at > buf.size) error(messageBuilder())
}
}
class SerializedInlineFunctionReference(val file: Int, val functionSignature: Int, val body: Int,
val startOffset: Int, val endOffset: Int,
val extensionReceiverSig: Int, val dispatchReceiverSig: Int,
val valueParameterSigs: IntArray, val typeParameterSigs: IntArray,
val defaultValues: IntArray)
internal object InlineFunctionBodyReferenceSerializer {
fun serialize(bodies: List<SerializedInlineFunctionReference>): ByteArray {
val size = bodies.sumOf {
Int.SIZE_BYTES * (10 + it.valueParameterSigs.size + it.typeParameterSigs.size + it.defaultValues.size)
}
val stream = ByteArrayStream(ByteArray(size))
bodies.forEach {
stream.writeInt(it.file)
stream.writeInt(it.functionSignature)
stream.writeInt(it.body)
stream.writeInt(it.startOffset)
stream.writeInt(it.endOffset)
stream.writeInt(it.extensionReceiverSig)
stream.writeInt(it.dispatchReceiverSig)
stream.writeInt(it.valueParameterSigs.size)
it.valueParameterSigs.forEach { sig -> stream.writeInt(sig) }
stream.writeInt(it.typeParameterSigs.size)
it.typeParameterSigs.forEach { sig -> stream.writeInt(sig) }
stream.writeInt(it.defaultValues.size)
it.defaultValues.forEach { stream.writeInt(it) }
}
return stream.buf
}
fun deserialize(data: ByteArray): List<SerializedInlineFunctionReference> {
val result = mutableListOf<SerializedInlineFunctionReference>()
val stream = ByteArrayStream(data)
while (stream.hasData()) {
val file = stream.readInt()
val functionSignature = stream.readInt()
val body = stream.readInt()
val startOffset = stream.readInt()
val endOffset = stream.readInt()
val extensionReceiverSig = stream.readInt()
val dispatchReceiverSig = stream.readInt()
val valueParameterSigsCount = stream.readInt()
val valueParameterSigs = IntArray(valueParameterSigsCount) { stream.readInt() }
val typeParameterSigsCount = stream.readInt()
val typeParameterSigs = IntArray(typeParameterSigsCount) { stream.readInt() }
val defaultValuesCount = stream.readInt()
val defaultValues = IntArray(defaultValuesCount) { stream.readInt() }
result.add(SerializedInlineFunctionReference(file, functionSignature, body, startOffset, endOffset,
extensionReceiverSig, dispatchReceiverSig, valueParameterSigs, typeParameterSigs, defaultValues))
}
return result
}
}
// [binaryType] is needed in case a field is of a private inline class type (which can't be deserialized).
// But it is safe to just set the field's type to the primitive type the inline class will be erased to.
class SerializedClassFieldInfo(val name: Int, val binaryType: Int, val type: Int, val flags: Int) {
companion object {
const val FLAG_IS_CONST = 1
const val FLAG_CONST_INITIALIZER = 2
}
}
class SerializedClassFields(val file: Int, val classSignature: Int,
val typeParameterSigs: IntArray, val fields: Array<SerializedClassFieldInfo>)
internal object ClassFieldsSerializer {
fun serialize(classFields: List<SerializedClassFields>): ByteArray {
val size = classFields.sumOf { Int.SIZE_BYTES * (4 + it.typeParameterSigs.size + it.fields.size * 4) }
val stream = ByteArrayStream(ByteArray(size))
classFields.forEach {
stream.writeInt(it.file)
stream.writeInt(it.classSignature)
stream.writeInt(it.typeParameterSigs.size)
it.typeParameterSigs.forEach { stream.writeInt(it) }
stream.writeInt(it.fields.size)
it.fields.forEach { field ->
stream.writeInt(field.name)
stream.writeInt(field.binaryType)
stream.writeInt(field.type)
stream.writeInt(field.flags)
}
}
return stream.buf
}
fun deserialize(data: ByteArray): List<SerializedClassFields> {
val result = mutableListOf<SerializedClassFields>()
val stream = ByteArrayStream(data)
while (stream.hasData()) {
val file = stream.readInt()
val classSignature = stream.readInt()
val typeParameterSigsCount = stream.readInt()
val typeParameterSigs = IntArray(typeParameterSigsCount) { stream.readInt() }
val fieldsCount = stream.readInt()
val fields = Array(fieldsCount) {
val name = stream.readInt()
val binaryType = stream.readInt()
val type = stream.readInt()
val flags = stream.readInt()
SerializedClassFieldInfo(name, binaryType, type, flags)
}
result.add(SerializedClassFields(file, classSignature, typeParameterSigs, fields))
}
return result
}
}
internal fun ProtoClass.findClass(irClass: IrClass, fileReader: IrLibraryFile, symbolDeserializer: IrSymbolDeserializer): ProtoClass {
val signature = irClass.symbol.signature ?: error("No signature for ${irClass.render()}")
var result: ProtoClass? = null
for (i in 0 until this.declarationCount) {
val child = this.getDeclaration(i)
if (child.declaratorCase != ProtoDeclaration.DeclaratorCase.IR_CLASS) continue
val childClass = child.irClass
val name = fileReader.string(child.irClass.name)
if (name == irClass.name.asString()) {
if (result == null)
result = childClass
else {
val resultIdSignature = symbolDeserializer.deserializeIdSignature(BinarySymbolData.decode(result.base.symbol).signatureId)
if (resultIdSignature == signature)
return result
result = childClass
}
}
}
return result ?: error("Class ${irClass.render()} is not found")
}
internal fun ProtoClass.findProperty(irProperty: IrProperty, fileReader: IrLibraryFile, symbolDeserializer: IrSymbolDeserializer): ProtoProperty {
val signature = irProperty.symbol.signature ?: error("No signature for ${irProperty.render()}")
var result: ProtoProperty? = null
for (i in 0 until this.declarationCount) {
val child = this.getDeclaration(i)
if (child.declaratorCase != ProtoDeclaration.DeclaratorCase.IR_PROPERTY) continue
val childProperty = child.irProperty
val name = fileReader.string(child.irProperty.name)
if (name == irProperty.name.asString()) {
if (result == null)
result = childProperty
else {
val resultIdSignature = symbolDeserializer.deserializeIdSignature(BinarySymbolData.decode(result.base.symbol).signatureId)
if (resultIdSignature == signature)
return result
result = childProperty
}
}
}
return result ?: error("Property ${irProperty.render()} is not found")
}
internal fun ProtoProperty.findAccessor(irProperty: IrProperty, irFunction: IrSimpleFunction): ProtoFunction {
if (irFunction == irProperty.getter)
return getter
require(irFunction == irProperty.setter) { "Accessor should be either a getter or a setter. ${irFunction.render()}" }
return setter
}
internal fun ProtoClass.findInlineFunction(irFunction: IrFunction, fileReader: IrLibraryFile, symbolDeserializer: IrSymbolDeserializer): ProtoFunction {
(irFunction as? IrSimpleFunction)?.correspondingPropertySymbol?.owner?.let { irProperty ->
return findProperty(irProperty, fileReader, symbolDeserializer).findAccessor(irProperty, irFunction)
}
val signature = irFunction.symbol.signature ?: error("No signature for ${irFunction.render()}")
var result: ProtoFunction? = null
for (i in 0 until this.declarationCount) {
val child = this.getDeclaration(i)
if (child.declaratorCase != ProtoDeclaration.DeclaratorCase.IR_FUNCTION) continue
val childFunction = child.irFunction
if (childFunction.base.valueParameterCount != irFunction.valueParameters.size) continue
if (childFunction.base.hasExtensionReceiver() xor (irFunction.extensionReceiverParameter != null)) continue
if (childFunction.base.hasDispatchReceiver() xor (irFunction.dispatchReceiverParameter != null)) continue
if (!FunctionFlags.decode(childFunction.base.base.flags).isInline) continue
val nameAndType = BinaryNameAndType.decode(childFunction.base.nameType)
val name = fileReader.string(nameAndType.nameIndex)
if (name == irFunction.name.asString()) {
if (result == null)
result = childFunction
else {
val resultIdSignature = symbolDeserializer.deserializeIdSignature(BinarySymbolData.decode(result.base.base.symbol).signatureId)
if (resultIdSignature == signature)
return result
result = childFunction
}
}
}
return result ?: error("Function ${irFunction.render()} is not found")
}
object KonanFakeOverrideClassFilter : FakeOverrideClassFilter { object KonanFakeOverrideClassFilter : FakeOverrideClassFilter {
private fun IdSignature.isInteropSignature(): Boolean = with(this) { private fun IdSignature.isInteropSignature(): Boolean = with(this) {
@@ -59,7 +303,7 @@ object KonanFakeOverrideClassFilter : FakeOverrideClassFilter {
.any { it.signature?.isInteropSignature() ?: false } .any { it.signature?.isInteropSignature() ?: false }
override fun needToConstructFakeOverrides(clazz: IrClass): Boolean { override fun needToConstructFakeOverrides(clazz: IrClass): Boolean {
return !clazz.hasInteropSuperClass() return !clazz.hasInteropSuperClass() && clazz !is IrLazyClass
} }
} }
@@ -74,6 +318,7 @@ internal class KonanIrLinker(
private val cenumsProvider: IrProviderForCEnumAndCStructStubs, private val cenumsProvider: IrProviderForCEnumAndCStructStubs,
exportedDependencies: List<ModuleDescriptor>, exportedDependencies: List<ModuleDescriptor>,
private val cachedLibraries: CachedLibraries, private val cachedLibraries: CachedLibraries,
private val lazyIrForCaches: Boolean,
override val userVisibleIrModulesSupport: UserVisibleIrModulesSupport override val userVisibleIrModulesSupport: UserVisibleIrModulesSupport
) : KotlinIrLinker(currentModule, messageLogger, builtIns, symbolTable, exportedDependencies) { ) : KotlinIrLinker(currentModule, messageLogger, builtIns, symbolTable, exportedDependencies) {
@@ -92,27 +337,205 @@ internal class KonanIrLinker(
override val fakeOverrideBuilder: FakeOverrideBuilder = override val fakeOverrideBuilder: FakeOverrideBuilder =
FakeOverrideBuilder(this, symbolTable, KonanManglerIr, IrTypeSystemContextImpl(builtIns), KonanFakeOverrideClassFilter) FakeOverrideBuilder(this, symbolTable, KonanManglerIr, IrTypeSystemContextImpl(builtIns), KonanFakeOverrideClassFilter)
override fun createModuleDeserializer(moduleDescriptor: ModuleDescriptor, klib: KotlinLibrary?, strategyResolver: (String) -> DeserializationStrategy): IrModuleDeserializer { val nonCachedLibraryModuleDeserializers = mutableMapOf<ModuleDescriptor, KonanModuleDeserializer>()
if (moduleDescriptor === forwardModuleDescriptor) { val cachedLibraryModuleDeserializers = mutableMapOf<ModuleDescriptor, KonanCachedLibraryModuleDeserializer>()
return forwardDeclarationDeserializer ?: error("forward declaration deserializer expected")
}
if (klib != null && klib.isInteropLibrary()) { override fun createModuleDeserializer(moduleDescriptor: ModuleDescriptor, klib: KotlinLibrary?, strategyResolver: (String) -> DeserializationStrategy) =
// See https://youtrack.jetbrains.com/issue/KT-43517. when {
// Disabling this flag forces linker to generate IR. moduleDescriptor === forwardModuleDescriptor -> {
val isCached = false //cachedLibraries.isLibraryCached(klib) forwardDeclarationDeserializer ?: error("forward declaration deserializer expected")
return KonanInteropModuleDeserializer(moduleDescriptor, klib, isCached) }
} klib == null -> {
error("Expecting kotlin library for $moduleDescriptor")
}
klib.isInteropLibrary() -> {
// See https://youtrack.jetbrains.com/issue/KT-43517.
// Disabling this flag forces linker to generate IR.
val isCached = false //cachedLibraries.isLibraryCached(klib)
KonanInteropModuleDeserializer(moduleDescriptor, klib, isCached)
}
lazyIrForCaches && cachedLibraries.isLibraryCached(klib) -> {
KonanCachedLibraryModuleDeserializer(moduleDescriptor, klib).also {
cachedLibraryModuleDeserializers[moduleDescriptor] = it
}
}
else -> {
KonanModuleDeserializer(moduleDescriptor, klib, strategyResolver).also {
nonCachedLibraryModuleDeserializers[moduleDescriptor] = it
}
}
}
return KonanModuleDeserializer(moduleDescriptor, klib ?: error("Expecting kotlin library"), strategyResolver) override fun postProcess() {
if (lazyIrForCaches)
stubGenerator.unboundSymbolGeneration = true
super.postProcess()
} }
private inner class KonanModuleDeserializer( private val IrClass.firstNonClassParent: IrDeclarationParent
get() {
var parent = parent
while (parent is IrClass) parent = parent.parent
return parent
}
private fun IrClass.getOuterClasses(takeOnlyInner: Boolean): List<IrClass> {
var outerClass = this
val outerClasses = mutableListOf(outerClass)
while (outerClass.isInner || !takeOnlyInner) {
outerClass = outerClass.parent as? IrClass ?: break
outerClasses.add(outerClass)
}
outerClasses.reverse()
return outerClasses
}
private val InvalidIndex = -1
inner class KonanModuleDeserializer(
moduleDescriptor: ModuleDescriptor, moduleDescriptor: ModuleDescriptor,
klib: KotlinLibrary, klib: KotlinLibrary,
strategyResolver: (String) -> DeserializationStrategy strategyResolver: (String) -> DeserializationStrategy
): BasicIrModuleDeserializer(this@KonanIrLinker, moduleDescriptor, klib, strategyResolver, klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT) { ): BasicIrModuleDeserializer(this@KonanIrLinker, moduleDescriptor, klib, strategyResolver, klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT) {
override val moduleFragment: IrModuleFragment = KonanIrModuleFragmentImpl(moduleDescriptor, builtIns, emptyList()) override val moduleFragment: IrModuleFragment = KonanIrModuleFragmentImpl(moduleDescriptor, builtIns, emptyList())
fun buildInlineFunctionReference(irFunction: IrFunction): SerializedInlineFunctionReference {
val signature = irFunction.symbol.signature
?: error("No signature for ${irFunction.render()}")
val topLevelSignature = signature.topLevelSignature()
val fileDeserializationState = moduleReversedFileIndex[topLevelSignature]
?: error("No file deserializer for ${topLevelSignature.render()}")
val declarationIndex = fileDeserializationState.fileDeserializer.reversedSignatureIndex[topLevelSignature]
?: error("No declaration for ${topLevelSignature.render()}")
val fileReader = fileDeserializationState.fileReader
val symbolDeserializer = fileDeserializationState.fileDeserializer.symbolDeserializer
val protoDeclaration = fileReader.declaration(declarationIndex)
val outerClasses = (irFunction.parent as? IrClass)?.getOuterClasses(takeOnlyInner = false) ?: emptyList()
require((outerClasses.getOrNull(0)?.parent ?: irFunction.parent) is IrFile) {
"Local inline functions are not supported: ${irFunction.render()}"
}
val typeParameterSigs = mutableListOf<Int>()
val protoFunction = if (outerClasses.isEmpty()) {
val irProperty = (irFunction as? IrSimpleFunction)?.correspondingPropertySymbol?.owner
if (irProperty == null)
protoDeclaration.irFunction
else protoDeclaration.irProperty.findAccessor(irProperty, irFunction)
} else {
val firstNotInnerClassIndex = outerClasses.indexOfLast { !it.isInner }
var protoClass = protoDeclaration.irClass
outerClasses.indices.forEach { classIndex ->
if (classIndex >= firstNotInnerClassIndex /* owner's type parameters are always accessible */) {
(0 until protoClass.typeParameterCount).mapTo(typeParameterSigs) {
BinarySymbolData.decode(protoClass.getTypeParameter(it).base.symbol).signatureId
}
}
if (classIndex < outerClasses.size - 1)
protoClass = protoClass.findClass(outerClasses[classIndex + 1], fileReader, symbolDeserializer)
}
protoClass.findInlineFunction(irFunction, fileReader, symbolDeserializer)
}
val functionSignature = BinarySymbolData.decode(protoFunction.base.base.symbol).signatureId
(0 until protoFunction.base.typeParameterCount).mapTo(typeParameterSigs) {
BinarySymbolData.decode(protoFunction.base.getTypeParameter(it).base.symbol).signatureId
}
val defaultValues = mutableListOf<Int>()
val valueParameterSigs = (0 until protoFunction.base.valueParameterCount).map {
val valueParameter = protoFunction.base.getValueParameter(it)
defaultValues.add(if (valueParameter.hasDefaultValue()) valueParameter.defaultValue else InvalidIndex)
BinarySymbolData.decode(valueParameter.base.symbol).signatureId
}
val extensionReceiverSig = irFunction.extensionReceiverParameter?.let {
BinarySymbolData.decode(protoFunction.base.extensionReceiver.base.symbol).signatureId
} ?: InvalidIndex
val dispatchReceiverSig = irFunction.dispatchReceiverParameter?.let {
BinarySymbolData.decode(protoFunction.base.dispatchReceiver.base.symbol).signatureId
} ?: InvalidIndex
return SerializedInlineFunctionReference(fileDeserializationState.fileIndex, functionSignature, protoFunction.base.body,
irFunction.startOffset, irFunction.endOffset, extensionReceiverSig, dispatchReceiverSig,
valueParameterSigs.toIntArray(), typeParameterSigs.toIntArray(), defaultValues.toIntArray())
}
fun buildClassFields(irClass: IrClass, fields: List<ClassLayoutBuilder.FieldInfo>): SerializedClassFields {
val signature = irClass.symbol.signature
?: error("No signature for ${irClass.render()}")
val topLevelSignature = signature.topLevelSignature()
val fileDeserializationState = moduleReversedFileIndex[topLevelSignature]
?: error("No file deserializer for ${topLevelSignature.render()}")
val fileDeserializer = fileDeserializationState.fileDeserializer
val declarationIndex = fileDeserializer.reversedSignatureIndex[topLevelSignature]
?: error("No declaration for ${topLevelSignature.render()}")
val fileReader = fileDeserializationState.fileReader
val symbolDeserializer = fileDeserializer.symbolDeserializer
val protoDeclaration = fileReader.declaration(declarationIndex)
val outerClasses = irClass.getOuterClasses(takeOnlyInner = false)
require(outerClasses.first().parent is IrFile) { "Local classes are not supported: ${irClass.render()}" }
val typeParameterSigs = mutableListOf<Int>()
var protoClass = protoDeclaration.irClass
val firstNotInnerClassIndex = outerClasses.indexOfLast { !it.isInner }
for (classIndex in outerClasses.indices) {
if (classIndex >= firstNotInnerClassIndex /* owner's type parameters are always accessible */) {
(0 until protoClass.typeParameterCount).mapTo(typeParameterSigs) {
BinarySymbolData.decode(protoClass.getTypeParameter(it).base.symbol).signatureId
}
}
if (classIndex < outerClasses.size - 1)
protoClass = protoClass.findClass(outerClasses[classIndex + 1], fileReader, symbolDeserializer)
}
val protoFields = mutableListOf<ProtoField>()
for (i in 0 until protoClass.declarationCount) {
val declaration = protoClass.getDeclaration(i)
if (declaration.declaratorCase == ProtoDeclaration.DeclaratorCase.IR_FIELD)
protoFields.add(declaration.irField)
else if (declaration.declaratorCase == ProtoDeclaration.DeclaratorCase.IR_PROPERTY) {
val protoProperty = declaration.irProperty
if (protoProperty.hasBackingField())
protoFields.add(protoProperty.backingField)
}
}
val protoFieldsMap = mutableMapOf<String, ProtoField>()
protoFields.forEach {
val nameAndType = BinaryNameAndType.decode(it.nameType)
val name = fileReader.string(nameAndType.nameIndex)
val prev = protoFieldsMap[name]
if (prev != null)
error("Class ${irClass.render()} has two fields with same name '$name'")
protoFieldsMap[name] = it
}
val compatibleMode = CompatibilityMode(libraryAbiVersion).oldSignatures
return SerializedClassFields(
fileDeserializationState.fileIndex,
BinarySymbolData.decode(protoClass.base.symbol).signatureId,
typeParameterSigs.toIntArray(),
Array(fields.size) {
val field = fields[it]
val irField = field.irField ?: error("No IR for field ${field.name} of ${irClass.render()}")
val protoField = protoFieldsMap[field.name] ?: error("No proto for ${irField.render()}")
val nameAndType = BinaryNameAndType.decode(protoField.nameType)
var flags = 0
if (field.isConst)
flags = flags or SerializedClassFieldInfo.FLAG_IS_CONST
if (field.hasConstInitializer)
flags = flags or SerializedClassFieldInfo.FLAG_CONST_INITIALIZER
val classifier = irField.type.classifierOrNull ?: error("Fields of type ${irField.type.render()} are not supported")
val primitiveBinaryType = irField.type.computePrimitiveBinaryTypeOrNull()
SerializedClassFieldInfo(
nameAndType.nameIndex,
primitiveBinaryType?.ordinal ?: InvalidIndex,
if (with(KonanManglerIr) { (classifier as? IrClassSymbol)?.owner?.isExported(compatibleMode) } == false)
InvalidIndex
else nameAndType.typeIndex,
flags)
})
}
} }
private inner class KonanInteropModuleDeserializer( private inner class KonanInteropModuleDeserializer(
@@ -121,14 +544,15 @@ internal class KonanIrLinker(
private val isLibraryCached: Boolean private val isLibraryCached: Boolean
) : IrModuleDeserializer(moduleDescriptor, klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT) { ) : IrModuleDeserializer(moduleDescriptor, klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT) {
init { init {
assert(klib.isInteropLibrary()) require(klib.isInteropLibrary())
} }
private val descriptorByIdSignatureFinder = DescriptorByIdSignatureFinder( private val descriptorByIdSignatureFinder = DescriptorByIdSignatureFinder(
moduleDescriptor, KonanManglerDesc, moduleDescriptor, KonanManglerDesc,
DescriptorByIdSignatureFinder.LookupMode.MODULE_ONLY DescriptorByIdSignatureFinder.LookupMode.MODULE_ONLY
) )
private fun IdSignature.isInteropSignature(): Boolean = IdSignature.Flags.IS_NATIVE_INTEROP_LIBRARY.test()
private fun IdSignature.isInteropSignature() = IdSignature.Flags.IS_NATIVE_INTEROP_LIBRARY.test()
override fun contains(idSig: IdSignature): Boolean { override fun contains(idSig: IdSignature): Boolean {
if (idSig.isPubliclyVisible) { if (idSig.isPubliclyVisible) {
@@ -170,9 +594,233 @@ internal class KonanIrLinker(
override val moduleDependencies: Collection<IrModuleDeserializer> = listOfNotNull(forwardDeclarationDeserializer) override val moduleDependencies: Collection<IrModuleDeserializer> = listOfNotNull(forwardDeclarationDeserializer)
} }
inner class KonanCachedLibraryModuleDeserializer(
moduleDescriptor: ModuleDescriptor,
override val klib: KotlinLibrary
) : IrModuleDeserializer(moduleDescriptor, klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT) {
private val descriptorByIdSignatureFinder = DescriptorByIdSignatureFinder(
moduleDescriptor, KonanManglerDesc,
DescriptorByIdSignatureFinder.LookupMode.MODULE_ONLY
)
override fun contains(idSig: IdSignature) =
idSig.isPubliclyVisible && descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) != null
override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
val descriptor = descriptorByIdSignatureFinder.findDescriptorBySignature(idSig)
?: error("Expecting descriptor for $idSig")
return (stubGenerator.generateMemberStub(descriptor) as IrSymbolOwner).symbol
}
override val moduleFragment: IrModuleFragment = KonanIrModuleFragmentImpl(moduleDescriptor, builtIns)
override val moduleDependencies by lazy {
moduleDescriptor.allDependencyModules
.filter { it != moduleDescriptor }
.map { resolveModuleDeserializer(it, null) }
}
inner class FileDeserializationInfo(val fileReader: IrLibraryFileFromBytes, val file: IrFile,
val declarationDeserializer: IrDeclarationDeserializer,
val fakeOverrideBuilder: FakeOverrideBuilder)
private val filesDeserializationInfo by lazy {
val result = mutableListOf<FileDeserializationInfo>()
val fileCount = klib.fileCount()
for (i in 0 until fileCount) {
val fileStream = klib.file(i).codedInputStream
val fileProto = ProtoFile.parseFrom(fileStream, ExtensionRegistryLite.newInstance())
val fileReader = IrLibraryFileFromBytes(IrKlibBytesSource(klib, i))
val file = fileReader.createFile(moduleFragment, fileProto)
val symbolDeserializer = IrSymbolDeserializer(
symbolTable, fileReader, file.symbol, emptyList(), { }, { _, symbol -> symbol })
{ idSig, symbolKind ->
val topLevelSig = idSig.topLevelSignature()
val actualModuleDeserializer = resolveModuleDeserializer(moduleDescriptor, null)
.findModuleDeserializerForTopLevelId(topLevelSig)
?: handleSignatureIdNotFoundInModuleWithDependencies(idSig, this)
actualModuleDeserializer.deserializeIrSymbol(idSig, symbolKind)
}
val fakeOverrideBuilder = FakeOverrideBuilder(
object : FileLocalAwareLinker {
override fun tryReferencingSimpleFunctionByLocalSignature(parent: IrDeclaration, idSignature: IdSignature) =
if (idSignature.isPubliclyVisible) null else symbolDeserializer.referenceSimpleFunctionByLocalSignature(idSignature)
override fun tryReferencingPropertyByLocalSignature(parent: IrDeclaration, idSignature: IdSignature) =
if (idSignature.isPubliclyVisible) null else symbolDeserializer.referencePropertyByLocalSignature(idSignature)
},
symbolTable, KonanManglerIr, IrTypeSystemContextImpl(builtIns), KonanFakeOverrideClassFilter)
val declarationDeserializer = IrDeclarationDeserializer(
builtIns,
symbolTable,
IrFactoryImpl,
fileReader,
file,
allowErrorNodes = false,
deserializeInlineFunctions = true,
deserializeBodies = true,
symbolDeserializer,
fakeOverrideBuilder.platformSpecificClassFilter,
fakeOverrideBuilder,
compatibilityMode = CompatibilityMode(libraryAbiVersion)
)
result.add(FileDeserializationInfo(fileReader, file, declarationDeserializer, fakeOverrideBuilder))
}
result
}
private val inlineFunctionReferences by lazy {
cachedLibraries.getLibraryCache(klib)!!.serializedInlineFunctionBodies.associateBy {
filesDeserializationInfo[it.file].declarationDeserializer.symbolDeserializer.deserializeIdSignature(it.functionSignature)
}
}
private val inlineFunctionFiles = mutableMapOf<IrExternalPackageFragment, IrFile>()
fun deserializeInlineFunction(function: IrFunction): InlineFunctionOriginInfo {
val packageFragment = function.findPackage() as? IrExternalPackageFragment
?: error("Expected an external package fragment for ${function.render()}")
if (function.parents.any { (it as? IrFunction)?.isInline == true}) {
// Already deserialized by the top-most inline function.
return InlineFunctionOriginInfo(
inlineFunctionFiles[packageFragment]
?: error("${function.render()} should've been deserialized along with its parent"),
function.startOffset, function.endOffset
)
}
val signature = function.symbol.signature
?: error("No signature for ${function.render()}")
val inlineFunctionReference = inlineFunctionReferences[signature]
?: error("No inline function reference for ${function.render()}, sig = ${signature.render()}")
val fileDeserializationInfo = filesDeserializationInfo[inlineFunctionReference.file]
val declarationDeserializer = fileDeserializationInfo.declarationDeserializer
val symbolDeserializer = declarationDeserializer.symbolDeserializer
val outerClasses = (function.parent as? IrClass)?.getOuterClasses(takeOnlyInner = true) ?: emptyList()
require((outerClasses.getOrNull(0)?.firstNonClassParent ?: function.parent) is IrExternalPackageFragment) {
"Local inline functions are not supported: ${function.render()}"
}
var endToEndTypeParameterIndex = 0
outerClasses.forEach { outerClass ->
outerClass.typeParameters.forEach { parameter ->
val sigIndex = inlineFunctionReference.typeParameterSigs[endToEndTypeParameterIndex++]
symbolDeserializer.referenceLocalIrSymbol(parameter.symbol, symbolDeserializer.deserializeIdSignature(sigIndex))
}
}
function.typeParameters.forEach { parameter ->
val sigIndex = inlineFunctionReference.typeParameterSigs[endToEndTypeParameterIndex++]
symbolDeserializer.referenceLocalIrSymbol(parameter.symbol, symbolDeserializer.deserializeIdSignature(sigIndex))
}
function.valueParameters.forEachIndexed { index, parameter ->
val sigIndex = inlineFunctionReference.valueParameterSigs[index]
symbolDeserializer.referenceLocalIrSymbol(parameter.symbol, symbolDeserializer.deserializeIdSignature(sigIndex))
}
function.extensionReceiverParameter?.let { parameter ->
val sigIndex = inlineFunctionReference.extensionReceiverSig
require(sigIndex != InvalidIndex) { "Expected a valid sig reference to the extension receiver for ${function.render()}" }
symbolDeserializer.referenceLocalIrSymbol(parameter.symbol, symbolDeserializer.deserializeIdSignature(sigIndex))
}
function.dispatchReceiverParameter?.let { parameter ->
val sigIndex = inlineFunctionReference.dispatchReceiverSig
require(sigIndex != InvalidIndex) { "Expected a valid sig reference to the dispatch receiver for ${function.render()}" }
symbolDeserializer.referenceLocalIrSymbol(parameter.symbol, symbolDeserializer.deserializeIdSignature(sigIndex))
}
function.body = declarationDeserializer.deserializeStatementBody(inlineFunctionReference.body) as IrBody
function.valueParameters.forEachIndexed { index, parameter ->
val defaultValueIndex = inlineFunctionReference.defaultValues[index]
if (defaultValueIndex != InvalidIndex)
parameter.defaultValue = declarationDeserializer.deserializeExpressionBody(defaultValueIndex)
}
fileDeserializationInfo.fakeOverrideBuilder.provideFakeOverrides()
inlineFunctionFiles[packageFragment]?.let {
require(it == fileDeserializationInfo.file) {
"Different files ${it.fileEntry.name} and ${fileDeserializationInfo.file.fileEntry.name} have the same $packageFragment"
}
}
inlineFunctionFiles[packageFragment] = fileDeserializationInfo.file
return InlineFunctionOriginInfo(fileDeserializationInfo.file, inlineFunctionReference.startOffset, inlineFunctionReference.endOffset)
}
private val classesFields by lazy {
cachedLibraries.getLibraryCache(klib)!!.serializedClassFields.associateBy {
filesDeserializationInfo[it.file].declarationDeserializer.symbolDeserializer.deserializeIdSignature(it.classSignature)
}
}
fun deserializeClassFields(irClass: IrClass): List<ClassLayoutBuilder.FieldInfo> {
val signature = irClass.symbol.signature
?: error("No signature for ${irClass.render()}")
val serializedClassFields = classesFields[signature]
?: error("No class fields for ${irClass.render()}, sig = ${signature.render()}")
val fileDeserializationInfo = filesDeserializationInfo[serializedClassFields.file]
val declarationDeserializer = fileDeserializationInfo.declarationDeserializer
val symbolDeserializer = declarationDeserializer.symbolDeserializer
val outerClasses = irClass.getOuterClasses(takeOnlyInner = true)
require(outerClasses.first().firstNonClassParent is IrExternalPackageFragment) {
"Local classes are not supported: ${irClass.render()}"
}
var endToEndTypeParameterIndex = 0
outerClasses.forEach { outerClass ->
outerClass.typeParameters.forEach { parameter ->
val sigIndex = serializedClassFields.typeParameterSigs[endToEndTypeParameterIndex++]
symbolDeserializer.referenceLocalIrSymbol(parameter.symbol, symbolDeserializer.deserializeIdSignature(sigIndex))
}
}
fun getByClassId(classId: ClassId): IrClassSymbol {
val classIdSig = getPublicSignature(classId.packageFqName, classId.relativeClassName.asString())
return symbolDeserializer.deserializePublicSymbol(classIdSig, BinarySymbolData.SymbolKind.CLASS_SYMBOL) as IrClassSymbol
}
return serializedClassFields.fields.map {
val name = fileDeserializationInfo.fileReader.string(it.name)
val type = when {
it.type != InvalidIndex -> declarationDeserializer.deserializeIrType(it.type)
it.binaryType == InvalidIndex -> builtIns.anyNType
else -> when (PrimitiveBinaryType.values().getOrNull(it.binaryType)) {
PrimitiveBinaryType.BOOLEAN -> builtIns.booleanType
PrimitiveBinaryType.BYTE -> builtIns.byteType
PrimitiveBinaryType.SHORT -> builtIns.shortType
PrimitiveBinaryType.INT -> builtIns.intType
PrimitiveBinaryType.LONG -> builtIns.longType
PrimitiveBinaryType.FLOAT -> builtIns.floatType
PrimitiveBinaryType.DOUBLE -> builtIns.doubleType
PrimitiveBinaryType.POINTER -> getByClassId(KonanPrimitiveType.NON_NULL_NATIVE_PTR.classId).defaultType
PrimitiveBinaryType.VECTOR128 -> getByClassId(KonanPrimitiveType.VECTOR128.classId).defaultType
else -> error("Bad binary type of field $name of ${irClass.render()}")
}
}
ClassLayoutBuilder.FieldInfo(
name, type,
isConst = (it.flags and SerializedClassFieldInfo.FLAG_IS_CONST) != 0,
hasConstInitializer = (it.flags and SerializedClassFieldInfo.FLAG_CONST_INITIALIZER) != 0,
irField = null)
}
}
}
private inner class KonanForwardDeclarationModuleDeserializer(moduleDescriptor: ModuleDescriptor) : IrModuleDeserializer(moduleDescriptor, KotlinAbiVersion.CURRENT) { private inner class KonanForwardDeclarationModuleDeserializer(moduleDescriptor: ModuleDescriptor) : IrModuleDeserializer(moduleDescriptor, KotlinAbiVersion.CURRENT) {
init { init {
assert(moduleDescriptor.isForwardDeclarationModule) require(moduleDescriptor.isForwardDeclarationModule)
} }
private val declaredDeclaration = mutableMapOf<IdSignature, IrClass>() private val declaredDeclaration = mutableMapOf<IdSignature, IrClass>()
@@ -190,10 +838,10 @@ internal class KonanIrLinker(
override fun contains(idSig: IdSignature): Boolean = idSig.isForwardDeclarationSignature() override fun contains(idSig: IdSignature): Boolean = idSig.isForwardDeclarationSignature()
private fun resolveDescriptor(idSig: IdSignature): ClassDescriptor = private fun resolveDescriptor(idSig: IdSignature): ClassDescriptor =
with(idSig as IdSignature.CommonSignature) { with(idSig as IdSignature.CommonSignature) {
val classId = ClassId(packageFqName(), FqName(declarationFqName), false) val classId = ClassId(packageFqName(), FqName(declarationFqName), false)
moduleDescriptor.findClassAcrossModuleDependencies(classId) ?: error("No declaration found with $idSig") moduleDescriptor.findClassAcrossModuleDependencies(classId) ?: error("No declaration found with $idSig")
} }
private fun buildForwardDeclarationStub(descriptor: ClassDescriptor): IrClass { private fun buildForwardDeclarationStub(descriptor: ClassDescriptor): IrClass {
return stubGenerator.generateClassStub(descriptor).also { return stubGenerator.generateClassStub(descriptor).also {
@@ -202,7 +850,9 @@ internal class KonanIrLinker(
} }
override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol { override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
assert(symbolKind == BinarySymbolData.SymbolKind.CLASS_SYMBOL) { "Only class could be a Forward declaration $idSig (kind $symbolKind)" } require(symbolKind == BinarySymbolData.SymbolKind.CLASS_SYMBOL) {
"Only class could be a Forward declaration $idSig (kind $symbolKind)"
}
val descriptor = resolveDescriptor(idSig) val descriptor = resolveDescriptor(idSig)
val actualModule = descriptor.module val actualModule = descriptor.module
if (actualModule !== moduleDescriptor) { if (actualModule !== moduleDescriptor) {