[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:
+1
-1
@@ -182,7 +182,7 @@ class FunctionInlining(
|
||||
val statements = (copiedCallee.body as IrBlockBody).statements
|
||||
|
||||
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
|
||||
* 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.DeserializableClass
|
||||
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.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
|
||||
@@ -79,7 +80,8 @@ class IrLazyClass(
|
||||
|
||||
private fun shouldBuildStub(descriptor: DeclarationDescriptor): Boolean =
|
||||
descriptor !is DeclarationDescriptorWithVisibility ||
|
||||
!DescriptorVisibilities.isPrivate(descriptor.visibility)
|
||||
!DescriptorVisibilities.isPrivate(descriptor.visibility) ||
|
||||
isObject && descriptor is ClassConstructorDescriptor
|
||||
|
||||
override var typeParameters: List<IrTypeParameter> by lazyVar(stubGenerator.lock) {
|
||||
descriptor.declaredTypeParameters.mapTo(arrayListOf()) {
|
||||
|
||||
+33
@@ -7,11 +7,15 @@ package org.jetbrains.kotlin.ir.declarations.lazy
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||
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.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
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.IrValueParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
|
||||
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.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)
|
||||
class IrLazyConstructor(
|
||||
override val startOffset: Int,
|
||||
|
||||
+21
-4
@@ -5,10 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.declarations.lazy
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.IrLock
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
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 {
|
||||
synchronized(lock) {
|
||||
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 {
|
||||
synchronized(lock) {
|
||||
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.IrFunctionSymbol
|
||||
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.visitors.IrElementTransformer
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
@@ -58,6 +58,5 @@ abstract class IrReturnableBlock : IrBlock(), IrSymbolOwner, IrReturnTarget {
|
||||
abstract val inlineFunctionSymbol: IrFunctionSymbol?
|
||||
}
|
||||
|
||||
@Suppress("unused") // Used in kotlin-native
|
||||
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 superArguments = superType.arguments
|
||||
assert(typeParameters.size == superArguments.size) {
|
||||
require(typeParameters.size == superArguments.size) {
|
||||
"typeParameters = $typeParameters size != typeArguments = $superArguments size "
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ fun buildFakeOverrideMember(superType: IrType, member: IrOverridableMember, claz
|
||||
val tp = typeParameters[i]
|
||||
val ta = superArguments[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
|
||||
}
|
||||
|
||||
@@ -414,7 +414,7 @@ class IrOverridingUtil(
|
||||
|
||||
fakeOverride.overriddenSymbols = effectiveOverridden.map { it.original.symbol }
|
||||
|
||||
assert(
|
||||
require(
|
||||
fakeOverride.overriddenSymbols.isNotEmpty()
|
||||
) { "Overridden symbols should be set for " + CallableMemberDescriptor.Kind.FAKE_OVERRIDE }
|
||||
|
||||
@@ -465,26 +465,24 @@ class IrOverridingUtil(
|
||||
val bReturnType = b.returnType
|
||||
if (!isVisibilityMoreSpecific(a, b)) return false
|
||||
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)
|
||||
}
|
||||
if (a is IrProperty) {
|
||||
assert(b is IrProperty) { "b is " + b.javaClass }
|
||||
val pa = a
|
||||
val pb = b as IrProperty
|
||||
require(b is IrProperty) { "b is " + b.javaClass }
|
||||
if (!isAccessorMoreSpecific(
|
||||
pa.setter,
|
||||
pb.setter
|
||||
a.setter,
|
||||
b.setter
|
||||
)
|
||||
) return false
|
||||
return if (pa.isVar && pb.isVar) {
|
||||
return if (a.isVar && b.isVar) {
|
||||
createTypeCheckerState(
|
||||
a.getter!!.typeParameters,
|
||||
b.getter!!.typeParameters
|
||||
).equalTypes(aReturnType, bReturnType)
|
||||
} else {
|
||||
// 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,
|
||||
b, bReturnType
|
||||
)
|
||||
@@ -510,7 +508,7 @@ class IrOverridingUtil(
|
||||
private fun selectMostSpecificMember(
|
||||
overridables: Collection<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) {
|
||||
return overridables.first()
|
||||
}
|
||||
@@ -693,7 +691,7 @@ class IrOverridingUtil(
|
||||
}
|
||||
*/
|
||||
|
||||
assert(superValueParameters.size == subValueParameters.size)
|
||||
require(superValueParameters.size == subValueParameters.size)
|
||||
|
||||
superValueParameters.forEachIndexed { index, parameter ->
|
||||
if (!AbstractTypeChecker.equalTypes(
|
||||
|
||||
@@ -235,10 +235,9 @@ abstract class DeclarationStubGenerator(
|
||||
private fun KotlinType.toIrType() = typeTranslator.translateType(this)
|
||||
|
||||
internal fun generateValueParameterStub(descriptor: ValueParameterDescriptor): IrValueParameter = with(descriptor) {
|
||||
symbolTable.irFactory.createValueParameter(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET, computeOrigin(this), IrValueParameterSymbolImpl(this), name, index, type.toIrType(),
|
||||
varargElementType?.toIrType(), isCrossinline, isNoinline, isHidden = false, isAssignable = false
|
||||
).also { irValueParameter ->
|
||||
IrLazyValueParameter(UNDEFINED_OFFSET, UNDEFINED_OFFSET, computeOrigin(this), IrValueParameterSymbolImpl(this), this, name, index,
|
||||
type.toIrType(), varargElementType?.toIrType(), isCrossinline, isNoinline, isHidden = false, isAssignable = false, this@DeclarationStubGenerator, typeTranslator)
|
||||
.also { irValueParameter ->
|
||||
if (descriptor.declaresDefaultValue()) {
|
||||
irValueParameter.defaultValue = irValueParameter.createStubDefaultValue()
|
||||
}
|
||||
@@ -304,7 +303,7 @@ abstract class DeclarationStubGenerator(
|
||||
}
|
||||
|
||||
internal fun generateOrGetScopedTypeParameterStub(descriptor: TypeParameterDescriptor): IrTypeParameter {
|
||||
val referenced = symbolTable.referenceTypeParameter(descriptor)
|
||||
val referenced = symbolTable.referenceScopedTypeParameter(descriptor)
|
||||
if (referenced.isBound) {
|
||||
return referenced.owner
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ interface ReferenceSymbolTable {
|
||||
fun referenceValueParameter(descriptor: ParameterDescriptor): IrValueParameterSymbol
|
||||
|
||||
fun referenceTypeParameter(classifier: TypeParameterDescriptor): IrTypeParameterSymbol
|
||||
fun referenceScopedTypeParameter(classifier: TypeParameterDescriptor): IrTypeParameterSymbol
|
||||
fun referenceVariable(descriptor: VariableDescriptor): IrVariableSymbol
|
||||
|
||||
fun referenceTypeAlias(descriptor: TypeAliasDescriptor): IrTypeAliasSymbol
|
||||
@@ -1030,6 +1031,11 @@ open class SymbolTable(
|
||||
createTypeParameterSymbol(classifier)
|
||||
}
|
||||
|
||||
override fun referenceScopedTypeParameter(classifier: TypeParameterDescriptor): IrTypeParameterSymbol =
|
||||
scopedTypeParameterSymbolTable.referenced(classifier) {
|
||||
createTypeParameterSymbol(classifier)
|
||||
}
|
||||
|
||||
override fun referenceGlobalTypeParameterFromLinker(sig: IdSignature): IrTypeParameterSymbol {
|
||||
return globalTypeParameterSymbolTable.referenced(sig, false) {
|
||||
if (sig.isPubliclyVisible) IrTypeParameterPublicSymbolImpl(sig) else IrTypeParameterSymbolImpl()
|
||||
|
||||
+2
-1
@@ -35,7 +35,7 @@ abstract class BasicIrModuleDeserializer(
|
||||
|
||||
private val moduleDeserializationState = ModuleDeserializationState(linker, this)
|
||||
|
||||
internal val moduleReversedFileIndex = mutableMapOf<IdSignature, FileDeserializationState>()
|
||||
val moduleReversedFileIndex = mutableMapOf<IdSignature, FileDeserializationState>()
|
||||
|
||||
override val moduleDependencies by lazy {
|
||||
moduleDescriptor.allDependencyModules.filter { it != moduleDescriptor }.map { linker.resolveModuleDeserializer(it, null) }
|
||||
@@ -110,6 +110,7 @@ abstract class BasicIrModuleDeserializer(
|
||||
|
||||
val fileDeserializationState = FileDeserializationState(
|
||||
linker,
|
||||
fileIndex,
|
||||
file,
|
||||
fileReader,
|
||||
fileProto,
|
||||
|
||||
+2
-1
@@ -57,8 +57,9 @@ class IrFileDeserializer(
|
||||
|
||||
class FileDeserializationState(
|
||||
val linker: KotlinIrLinker,
|
||||
val fileIndex: Int,
|
||||
file: IrFile,
|
||||
fileReader: IrLibraryFileFromBytes,
|
||||
val fileReader: IrLibraryFileFromBytes,
|
||||
fileProto: ProtoFile,
|
||||
deserializeBodies: Boolean,
|
||||
allowErrorNodes: Boolean,
|
||||
|
||||
+1
@@ -22,6 +22,7 @@ internal fun IrSymbol.kind(): BinarySymbolData.SymbolKind {
|
||||
is IrPropertySymbol -> BinarySymbolData.SymbolKind.PROPERTY_SYMBOL
|
||||
is IrEnumEntrySymbol -> BinarySymbolData.SymbolKind.ENUM_ENTRY_SYMBOL
|
||||
is IrTypeAliasSymbol -> BinarySymbolData.SymbolKind.TYPEALIAS_SYMBOL
|
||||
is IrTypeParameterSymbol -> BinarySymbolData.SymbolKind.TYPE_PARAMETER_SYMBOL
|
||||
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
|
||||
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
|
||||
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]
|
||||
FIELD IR_EXTERNAL_DECLARATION_STUB name:MAX_VALUE type:kotlin.Int visibility:public [final]
|
||||
EXPRESSION_BODY
|
||||
|
||||
@@ -364,6 +364,15 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
||||
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) }
|
||||
putIfNotNull(LLVM_VARIANT, when (val variant = arguments.llvmVariant) {
|
||||
|
||||
+3
@@ -361,6 +361,9 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
|
||||
@Argument(value = "-Xruntime-logs", valueDescription = "<tag1=level1,tag2=level2,...>", description = "Enable logging for runtime with tags.")
|
||||
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> =
|
||||
super.configureAnalysisFlags(collector, languageVersion).also {
|
||||
val optInList = it[AnalysisFlags.optIn] as List<*>
|
||||
|
||||
+4
-4
@@ -53,7 +53,7 @@ internal val Context.getBoxFunction: (IrClass) -> IrSimpleFunction by Context.la
|
||||
classes.add(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
|
||||
|
||||
@@ -100,7 +100,7 @@ internal val Context.getBoxFunction: (IrClass) -> IrSimpleFunction by Context.la
|
||||
).also {
|
||||
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)
|
||||
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
|
||||
|
||||
@@ -159,7 +159,7 @@ internal val Context.getUnboxFunction: (IrClass) -> IrSimpleFunction by Context.
|
||||
).also {
|
||||
it.parent = function
|
||||
})
|
||||
function.parent = inlinedClass.getContainingFile()!!
|
||||
function.parent = parent
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+66
-27
@@ -36,11 +36,65 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
internal object DECLARATION_ORIGIN_FUNCTION_CLASS : IrDeclarationOriginImpl("DECLARATION_ORIGIN_FUNCTION_CLASS")
|
||||
|
||||
internal class BuiltInFictitiousFunctionIrClassFactory(
|
||||
var symbolTable: SymbolTable?,
|
||||
abstract class KonanIrAbstractDescriptorBasedFunctionFactory : IrProvider, IrAbstractDescriptorBasedFunctionFactory()
|
||||
|
||||
internal class LazyIrFunctionFactory(
|
||||
private val symbolTable: SymbolTable,
|
||||
private val stubGenerator: DeclarationStubGenerator,
|
||||
private val irBuiltIns: IrBuiltInsOverDescriptors,
|
||||
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) =
|
||||
(symbol.descriptor as? FunctionClassDescriptor)?.let { descriptor ->
|
||||
@@ -98,11 +152,11 @@ internal class BuiltInFictitiousFunctionIrClassFactory(
|
||||
override fun kSuspendFunctionN(arity: Int, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass =
|
||||
buildClass(reflectionTypes.getKSuspendFunction(arity) as FunctionClassDescriptor, declarator)
|
||||
|
||||
private val functionSymbol = symbolTable!!.referenceClass(
|
||||
private val functionSymbol = symbolTable.referenceClass(
|
||||
irBuiltIns.builtIns.builtInsModule.findClassAcrossModuleDependencies(
|
||||
ClassId.topLevel(KonanFqNames.function))!!)
|
||||
|
||||
private val kFunctionSymbol = symbolTable!!.referenceClass(
|
||||
private val kFunctionSymbol = symbolTable.referenceClass(
|
||||
irBuiltIns.builtIns.builtInsModule.findClassAcrossModuleDependencies(
|
||||
ClassId.topLevel(KonanFqNames.kFunction))!!)
|
||||
|
||||
@@ -121,20 +175,10 @@ internal class BuiltInFictitiousFunctionIrClassFactory(
|
||||
}
|
||||
|
||||
private fun createTypeParameter(descriptor: TypeParameterDescriptor): IrTypeParameter =
|
||||
symbolTable?.declareGlobalTypeParameter(
|
||||
symbolTable.declareGlobalTypeParameter(
|
||||
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, DECLARATION_ORIGIN_FUNCTION_CLASS,
|
||||
descriptor
|
||||
)
|
||||
?: IrTypeParameterImpl(
|
||||
SYNTHETIC_OFFSET,
|
||||
SYNTHETIC_OFFSET,
|
||||
DECLARATION_ORIGIN_FUNCTION_CLASS,
|
||||
IrTypeParameterSymbolImpl(descriptor),
|
||||
descriptor.name,
|
||||
descriptor.index,
|
||||
descriptor.isReified,
|
||||
descriptor.variance
|
||||
)
|
||||
|
||||
private fun createSimpleFunction(
|
||||
descriptor: FunctionDescriptor,
|
||||
@@ -150,16 +194,14 @@ internal class BuiltInFictitiousFunctionIrClassFactory(
|
||||
)
|
||||
}
|
||||
}
|
||||
return symbolTable?.declareSimpleFunction(descriptor, functionFactory)
|
||||
?: functionFactory(IrSimpleFunctionSymbolImpl(descriptor))
|
||||
return symbolTable.declareSimpleFunction(descriptor, functionFactory)
|
||||
}
|
||||
|
||||
private fun createIrClass(symbol: IrClassSymbol, descriptor: ClassDescriptor): IrClass =
|
||||
IrFactoryImpl.createIrClassFromDescriptor(offset, offset, DECLARATION_ORIGIN_FUNCTION_CLASS, symbol, descriptor)
|
||||
|
||||
private fun createClass(descriptor: FunctionClassDescriptor, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass =
|
||||
symbolTable?.declarator { createIrClass(it, descriptor) }
|
||||
?: createIrClass(IrClassSymbolImpl(descriptor), descriptor)
|
||||
symbolTable.declarator { createIrClass(it, descriptor) }
|
||||
|
||||
private fun buildClass(descriptor: FunctionClassDescriptor, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass =
|
||||
builtClassesMap.getOrPut(descriptor) {
|
||||
@@ -246,8 +288,7 @@ internal class BuiltInFictitiousFunctionIrClassFactory(
|
||||
private fun toIrType(wrapped: KotlinType): IrType {
|
||||
val kotlinType = wrapped.unwrap()
|
||||
return with(IrSimpleTypeBuilder()) {
|
||||
classifier =
|
||||
symbolTable?.referenceClassifier(kotlinType.constructor.declarationDescriptor ?: error("No classifier for type $kotlinType"))
|
||||
classifier = symbolTable.referenceClassifier(kotlinType.constructor.declarationDescriptor ?: error("No classifier for type $kotlinType"))
|
||||
hasQuestionMark = kotlinType.isMarkedNullable
|
||||
arguments = kotlinType.arguments.map {
|
||||
if (it.isStarProjection) IrStarProjectionImpl
|
||||
@@ -296,11 +337,10 @@ internal class BuiltInFictitiousFunctionIrClassFactory(
|
||||
}
|
||||
}
|
||||
|
||||
val newFunction = symbolTable?.declareSimpleFunction(descriptor, functionDeclare)
|
||||
?: functionDeclare(IrSimpleFunctionSymbolImpl(descriptor))
|
||||
val newFunction = symbolTable.declareSimpleFunction(descriptor, functionDeclare)
|
||||
|
||||
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.extensionReceiverParameter = descriptor.extensionReceiverParameter?.let { newFunction.createValueParameter(it) }
|
||||
newFunction.valueParameters = descriptor.valueParameters.map { newFunction.createValueParameter(it) }
|
||||
@@ -327,8 +367,7 @@ internal class BuiltInFictitiousFunctionIrClassFactory(
|
||||
isExpect = descriptor.isExpect,
|
||||
isFakeOverride = true)
|
||||
}
|
||||
val property = symbolTable?.declareProperty(offset, offset, memberOrigin, descriptor, propertyFactory = propertyDeclare)
|
||||
?: propertyDeclare(IrPropertySymbolImpl(descriptor))
|
||||
val property = symbolTable.declareProperty(offset, offset, memberOrigin, descriptor, propertyFactory = propertyDeclare)
|
||||
|
||||
property.parent = this
|
||||
property.getter = descriptor.getter?.let { g -> createFakeOverrideFunction(g, property.symbol) }
|
||||
|
||||
+17
@@ -5,6 +5,8 @@
|
||||
|
||||
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.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
@@ -25,6 +27,18 @@ class CachedLibraries(
|
||||
val directory = File(path).absoluteFile.parent
|
||||
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>>()
|
||||
@@ -90,6 +104,9 @@ class CachedLibraries(
|
||||
companion object {
|
||||
fun getCachedLibraryName(library: KotlinLibrary): String = getCachedLibraryName(library.uniqueName)
|
||||
fun getCachedLibraryName(libraryName: String): String = "$libraryName-cache"
|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
||||
+12
-1
@@ -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.konan.objcexport.ObjCExport
|
||||
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.symbols.IrSymbol
|
||||
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.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.
|
||||
*/
|
||||
@@ -65,7 +70,7 @@ internal class SpecialDeclarationsFactory(val context: Context) {
|
||||
|
||||
private val bridges = mutableMapOf<BridgeKey, IrSimpleFunction>()
|
||||
|
||||
val loweredInlineFunctions = mutableSetOf<IrFunction>()
|
||||
val loweredInlineFunctions = mutableMapOf<IrFunction, InlineFunctionOriginInfo>()
|
||||
|
||||
object DECLARATION_ORIGIN_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.
|
||||
*/
|
||||
val internalAbi = InternalAbi(this)
|
||||
|
||||
lateinit var irLinker: KonanIrLinker
|
||||
|
||||
val inlineFunctionBodies = mutableListOf<SerializedInlineFunctionReference>()
|
||||
|
||||
val classFields = mutableListOf<SerializedClassFields>()
|
||||
}
|
||||
|
||||
private fun MemberScope.getContributedClassifier(name: String) =
|
||||
|
||||
+15
-9
@@ -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.IrValueParameterSymbolImpl
|
||||
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.name.Name
|
||||
|
||||
internal fun makeEntryPoint(context: Context): IrFunction {
|
||||
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(
|
||||
actualMain.startOffset,
|
||||
actualMain.startOffset,
|
||||
startOffset,
|
||||
endOffset,
|
||||
IrDeclarationOrigin.DEFINED,
|
||||
IrSimpleFunctionSymbolImpl(),
|
||||
Name.identifier("Konan_start"),
|
||||
@@ -44,7 +54,7 @@ internal fun makeEntryPoint(context: Context): IrFunction {
|
||||
).also { function ->
|
||||
function.valueParameters = listOf(
|
||||
IrValueParameterImpl(
|
||||
actualMain.startOffset, actualMain.startOffset,
|
||||
startOffset, endOffset,
|
||||
IrDeclarationOrigin.DEFINED,
|
||||
IrValueParameterSymbolImpl(),
|
||||
Name.identifier("args"),
|
||||
@@ -60,16 +70,12 @@ internal fun makeEntryPoint(context: Context): IrFunction {
|
||||
})
|
||||
}
|
||||
entryPoint.annotations += buildSimpleAnnotation(context.irBuiltIns,
|
||||
actualMain.startOffset, actualMain.startOffset,
|
||||
startOffset, endOffset,
|
||||
context.ir.symbols.exportForCppRuntime.owner, "Konan_start")
|
||||
|
||||
val builder = context.createIrBuilder(entryPoint.symbol)
|
||||
entryPoint.body = builder.irBlockBody(entryPoint) {
|
||||
+IrTryImpl(
|
||||
startOffset = actualMain.startOffset,
|
||||
endOffset = actualMain.startOffset,
|
||||
type = context.irBuiltIns.nothingType
|
||||
).apply {
|
||||
+IrTryImpl(startOffset, endOffset, context.irBuiltIns.nothingType).apply {
|
||||
tryResult = irBlock {
|
||||
+irCall(actualMain).apply {
|
||||
if (actualMain.valueParameters.size != 0)
|
||||
|
||||
+2
@@ -273,6 +273,8 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
||||
internal val isInteropStubs: Boolean get() = manifestProperties?.getProperty("interop") == "true"
|
||||
|
||||
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)
|
||||
|
||||
+1
@@ -170,6 +170,7 @@ class KonanConfigKeys {
|
||||
CompilerConfigurationKey.create("use external dependencies to enhance IR linker error messages")
|
||||
val LLVM_VARIANT: CompilerConfigurationKey<LlvmVariant?> = CompilerConfigurationKey.create("llvm variant")
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
@@ -1,5 +1,7 @@
|
||||
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.exec.Command
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
@@ -58,6 +60,8 @@ internal class Linker(val context: Context) {
|
||||
|
||||
private fun saveAdditionalInfoForCache() {
|
||||
saveCacheBitcodeDependencies()
|
||||
saveInlineFunctionBodies()
|
||||
saveClassFields()
|
||||
}
|
||||
|
||||
private fun saveCacheBitcodeDependencies() {
|
||||
@@ -73,6 +77,18 @@ internal class Linker(val context: Context) {
|
||||
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() {
|
||||
if (context.config.produce.isCache) {
|
||||
val outputFiles = context.config.outputFiles
|
||||
|
||||
+10
@@ -63,6 +63,16 @@ class OutputFiles(outputPath: String?, target: KonanTarget, val produce: Compile
|
||||
tempCacheDirectory!!.child(CachedLibraries.BITCODE_DEPENDENCIES_FILE_NAME).absolutePath
|
||||
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.prefixBaseNameIfNeeded(prefix: String) =
|
||||
|
||||
+25
-18
@@ -53,15 +53,17 @@ internal fun Context.psiToIr(
|
||||
|
||||
// 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(
|
||||
moduleDescriptor, symbolTable,
|
||||
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 irDeserializer = if (isProducingLibrary && !useLinkerWhenProducingLibrary) {
|
||||
@@ -77,6 +79,7 @@ internal fun Context.psiToIr(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val exportedDependencies = (getExportedDependencies() + modulesWithoutDCE).distinct()
|
||||
val irProviderForCEnumsAndCStructs =
|
||||
IrProviderForCEnumAndCStructStubs(generatorContext, interopBuiltIns, symbols)
|
||||
|
||||
@@ -102,6 +105,7 @@ internal fun Context.psiToIr(
|
||||
irProviderForCEnumsAndCStructs,
|
||||
exportedDependencies,
|
||||
config.cachedLibraries,
|
||||
config.lazyIrForCaches,
|
||||
config.userVisibleIrModulesSupport
|
||||
).also { linker ->
|
||||
|
||||
@@ -120,15 +124,14 @@ internal fun Context.psiToIr(
|
||||
}
|
||||
|
||||
for (dependency in sortDependencies(dependencies).filter { it != moduleDescriptor }) {
|
||||
val kotlinLibrary = dependency.getCapability(KlibModuleOrigin.CAPABILITY)?.let {
|
||||
(it as? DeserializedKlibModuleOrigin)?.library
|
||||
}
|
||||
when {
|
||||
isProducingLibrary -> linker.deserializeOnlyHeaderModule(dependency, kotlinLibrary)
|
||||
kotlinLibrary != null && config.cachedLibraries.isLibraryCached(kotlinLibrary) ->
|
||||
linker.deserializeHeadersWithInlineBodies(dependency, kotlinLibrary)
|
||||
else -> linker.deserializeIrModuleHeader(dependency, kotlinLibrary, dependency.name.asString())
|
||||
}
|
||||
val kotlinLibrary = (dependency.getCapability(KlibModuleOrigin.CAPABILITY) as? DeserializedKlibModuleOrigin)?.library
|
||||
val isCachedLibrary = kotlinLibrary != null && config.cachedLibraries.isLibraryCached(kotlinLibrary)
|
||||
if (isProducingLibrary || (config.lazyIrForCaches && isCachedLibrary))
|
||||
linker.deserializeOnlyHeaderModule(dependency, kotlinLibrary)
|
||||
else if (isCachedLibrary)
|
||||
linker.deserializeHeadersWithInlineBodies(dependency, kotlinLibrary!!)
|
||||
else
|
||||
linker.deserializeIrModuleHeader(dependency, kotlinLibrary, dependency.name.asString())
|
||||
}
|
||||
if (dependencies.size == dependenciesCount) break
|
||||
dependenciesCount = dependencies.size
|
||||
@@ -140,7 +143,6 @@ internal fun Context.psiToIr(
|
||||
.filter(ModuleDescriptor::isFromInteropLibrary)
|
||||
.forEach(irProviderForCEnumsAndCStructs::referenceAllEnumsAndStructsFrom)
|
||||
|
||||
|
||||
translator.addPostprocessingStep {
|
||||
irProviderForCEnumsAndCStructs.generateBodies()
|
||||
}
|
||||
@@ -197,14 +199,19 @@ internal fun Context.psiToIr(
|
||||
// Note: coupled with [shouldLower] below.
|
||||
irModules = modules.filterValues { llvmModuleSpecification.containsModule(it) }
|
||||
|
||||
if (!isProducingLibrary)
|
||||
irLinker = irDeserializer as KonanIrLinker
|
||||
|
||||
ir.symbols = symbols
|
||||
|
||||
if (!isProducingLibrary) {
|
||||
// TODO: find out what should be done in the new builtins/symbols about it
|
||||
if (this.stdlibModule in modulesWithoutDCE)
|
||||
functionIrClassFactory.buildAllClasses()
|
||||
if (this.stdlibModule in modulesWithoutDCE) {
|
||||
(functionIrClassFactory as BuiltInFictitiousFunctionIrClassFactory).buildAllClasses()
|
||||
}
|
||||
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) }
|
||||
|
||||
+51
-12
@@ -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.serialization.CompatibilityMode
|
||||
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.lower.ExpectToActualDefaultValueCopier
|
||||
import org.jetbrains.kotlin.backend.konan.lower.SamSuperTypesChecker
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.KonanIdSignaturer
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.KonanIrModuleSerializer
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.KonanManglerDesc
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.*
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
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.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
internal fun moduleValidationCallback(state: ActionState, module: IrModuleFragment, context: Context) {
|
||||
if (!context.config.needVerifyIr) return
|
||||
@@ -124,6 +124,47 @@ internal val psiToIrPhase = konanUnitPhase(
|
||||
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.
|
||||
internal fun shouldLower(context: Context, declaration: IrDeclaration): Boolean {
|
||||
return context.llvmModuleSpecification.containsDeclaration(declaration)
|
||||
@@ -305,21 +346,17 @@ internal val entryPointPhase = makeCustomPhase<Context, IrModuleFragment>(
|
||||
description = "Add entry point for program",
|
||||
prerequisite = emptySet(),
|
||||
op = { context, _ ->
|
||||
assert(context.config.produce == CompilerOutputKind.PROGRAM)
|
||||
require(context.config.produce == CompilerOutputKind.PROGRAM)
|
||||
|
||||
val originalFile = context.ir.symbols.entryPoint!!.owner.file
|
||||
val originalModule = originalFile.packageFragmentDescriptor.containingDeclaration
|
||||
val file = if (context.llvmModuleSpecification.containsModule(originalModule)) {
|
||||
originalFile
|
||||
val entryPoint = context.ir.symbols.entryPoint!!.owner
|
||||
val file = if (context.llvmModuleSpecification.containsDeclaration(entryPoint)) {
|
||||
entryPoint.file
|
||||
} else {
|
||||
// `main` function is compiled to other LLVM module.
|
||||
// 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))
|
||||
}
|
||||
)
|
||||
@@ -444,6 +481,7 @@ val toplevelPhase: CompilerPhase<*, Unit, Unit> = namedUnitPhase(
|
||||
objCExportPhase then
|
||||
buildCExportsPhase then
|
||||
psiToIrPhase then
|
||||
buildAdditionalCacheInfoPhase then
|
||||
destroySymbolTablePhase then
|
||||
copyDefaultValuesToActualPhase then
|
||||
checkSamSuperTypesPhase then
|
||||
@@ -478,6 +516,7 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
|
||||
// Don't serialize anything to a final executable.
|
||||
disableUnless(serializerPhase, config.produce == CompilerOutputKind.LIBRARY)
|
||||
disableUnless(entryPointPhase, config.produce == CompilerOutputKind.PROGRAM)
|
||||
disableUnless(buildAdditionalCacheInfoPhase, config.produce.isCache)
|
||||
disableUnless(exportInternalAbiPhase, config.produce.isCache)
|
||||
disableIf(backendCodegen, config.produce == CompilerOutputKind.LIBRARY)
|
||||
disableUnless(bitcodeOptimizationPhase, config.produce.involvesLinkStage)
|
||||
|
||||
+14
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.library.isInterop
|
||||
|
||||
internal class OverriddenFunctionInfo(
|
||||
val function: IrSimpleFunction,
|
||||
@@ -466,6 +467,19 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context, va
|
||||
* Fields declared in the class.
|
||||
*/
|
||||
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) {
|
||||
// Note: copying to avoid mutation of the original class.
|
||||
irClass.declarations.toMutableList()
|
||||
|
||||
+2
-6
@@ -6,20 +6,16 @@
|
||||
package org.jetbrains.kotlin.backend.konan.ir
|
||||
|
||||
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.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyDeclarationBase
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.toKotlinType
|
||||
import org.jetbrains.kotlin.ir.util.file
|
||||
|
||||
// This file contains some IR utilities which actually use descriptors.
|
||||
// TODO: port this code to IR.
|
||||
|
||||
internal val IrDeclaration.llvmSymbolOrigin get() = when (this) {
|
||||
is IrLazyDeclarationBase -> descriptor.llvmSymbolOrigin
|
||||
else -> file.packageFragmentDescriptor.llvmSymbolOrigin
|
||||
}
|
||||
internal val IrDeclaration.llvmSymbolOrigin get() = findPackage().packageFragmentDescriptor.llvmSymbolOrigin
|
||||
|
||||
internal fun IrType.isObjCObjectType() = this.toKotlinType().isObjCObjectType()
|
||||
|
||||
|
||||
+12
-4
@@ -1824,15 +1824,23 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
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 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 {
|
||||
val location = returnableBlock.inlineFunctionSymbol?.let {
|
||||
location(it.owner.endOffset)
|
||||
val location = returnableBlock.inlineFunctionSymbol?.owner?.let {
|
||||
location(context.specialDeclarationsFactory.loweredInlineFunctions[it]?.endOffset ?: it.endOffset)
|
||||
} ?: returnableBlock.statements.lastOrNull()?.let {
|
||||
location(it.endOffset)
|
||||
}
|
||||
|
||||
+19
-6
@@ -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.LocalClassesInInlineLambdasLowering
|
||||
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.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.util.dump
|
||||
import org.jetbrains.kotlin.ir.util.file
|
||||
import org.jetbrains.kotlin.ir.util.fileOrNull
|
||||
import org.jetbrains.kotlin.ir.util.getPackageFragment
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
|
||||
// TODO: This is a bit hacky. Think about adopting persistent IR ideas.
|
||||
internal class NativeInlineFunctionResolver(override val context: Context) : DefaultInlineFunctionResolver(context) {
|
||||
override fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction {
|
||||
val function = super.getFunctionDeclaration(symbol)
|
||||
val body = function.body ?: return function
|
||||
|
||||
if (function in context.specialDeclarationsFactory.loweredInlineFunctions)
|
||||
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)
|
||||
|
||||
@@ -44,7 +57,7 @@ internal class NativeInlineFunctionResolver(override val context: Context) : Def
|
||||
|
||||
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.
|
||||
LocalClassesInInlineFunctionsLowering(context).lower(body, function)
|
||||
LocalClassesExtractionFromInlineFunctionsLowering(context).lower(body, function)
|
||||
|
||||
+5
-2
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
|
||||
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
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.expressions.IrBody
|
||||
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 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> {
|
||||
override fun visitDeclaration(declaration: IrDeclarationBase, data: IrBuilderWithScope) =
|
||||
super.visitDeclaration(declaration,
|
||||
@@ -53,7 +56,7 @@ internal class PreInlineLowering(val context: Context) : BodyLoweringPass {
|
||||
IrCompositeImpl(expression.startOffset, expression.endOffset, expression.type)
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
+672
-22
@@ -16,12 +16,20 @@
|
||||
|
||||
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.FakeOverrideClassFilter
|
||||
import org.jetbrains.kotlin.backend.common.overrides.FileLocalAwareLinker
|
||||
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.linkerissues.UserVisibleIrModulesSupport
|
||||
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.ir.interop.IrProviderForCEnumAndCStructStubs
|
||||
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.builders.TranslationPluginContext
|
||||
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.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.types.IrTypeSystemContextImpl
|
||||
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.visitors.IrElementTransformer
|
||||
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.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
|
||||
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 {
|
||||
private fun IdSignature.isInteropSignature(): Boolean = with(this) {
|
||||
@@ -59,7 +303,7 @@ object KonanFakeOverrideClassFilter : FakeOverrideClassFilter {
|
||||
.any { it.signature?.isInteropSignature() ?: false }
|
||||
|
||||
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,
|
||||
exportedDependencies: List<ModuleDescriptor>,
|
||||
private val cachedLibraries: CachedLibraries,
|
||||
private val lazyIrForCaches: Boolean,
|
||||
override val userVisibleIrModulesSupport: UserVisibleIrModulesSupport
|
||||
) : KotlinIrLinker(currentModule, messageLogger, builtIns, symbolTable, exportedDependencies) {
|
||||
|
||||
@@ -92,27 +337,205 @@ internal class KonanIrLinker(
|
||||
override val fakeOverrideBuilder: FakeOverrideBuilder =
|
||||
FakeOverrideBuilder(this, symbolTable, KonanManglerIr, IrTypeSystemContextImpl(builtIns), KonanFakeOverrideClassFilter)
|
||||
|
||||
override fun createModuleDeserializer(moduleDescriptor: ModuleDescriptor, klib: KotlinLibrary?, strategyResolver: (String) -> DeserializationStrategy): IrModuleDeserializer {
|
||||
if (moduleDescriptor === forwardModuleDescriptor) {
|
||||
return forwardDeclarationDeserializer ?: error("forward declaration deserializer expected")
|
||||
}
|
||||
val nonCachedLibraryModuleDeserializers = mutableMapOf<ModuleDescriptor, KonanModuleDeserializer>()
|
||||
val cachedLibraryModuleDeserializers = mutableMapOf<ModuleDescriptor, KonanCachedLibraryModuleDeserializer>()
|
||||
|
||||
if (klib != null && klib.isInteropLibrary()) {
|
||||
// See https://youtrack.jetbrains.com/issue/KT-43517.
|
||||
// Disabling this flag forces linker to generate IR.
|
||||
val isCached = false //cachedLibraries.isLibraryCached(klib)
|
||||
return KonanInteropModuleDeserializer(moduleDescriptor, klib, isCached)
|
||||
}
|
||||
override fun createModuleDeserializer(moduleDescriptor: ModuleDescriptor, klib: KotlinLibrary?, strategyResolver: (String) -> DeserializationStrategy) =
|
||||
when {
|
||||
moduleDescriptor === forwardModuleDescriptor -> {
|
||||
forwardDeclarationDeserializer ?: error("forward declaration deserializer expected")
|
||||
}
|
||||
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,
|
||||
klib: KotlinLibrary,
|
||||
strategyResolver: (String) -> DeserializationStrategy
|
||||
): BasicIrModuleDeserializer(this@KonanIrLinker, moduleDescriptor, klib, strategyResolver, klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT) {
|
||||
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(
|
||||
@@ -121,14 +544,15 @@ internal class KonanIrLinker(
|
||||
private val isLibraryCached: Boolean
|
||||
) : IrModuleDeserializer(moduleDescriptor, klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT) {
|
||||
init {
|
||||
assert(klib.isInteropLibrary())
|
||||
require(klib.isInteropLibrary())
|
||||
}
|
||||
|
||||
private val descriptorByIdSignatureFinder = DescriptorByIdSignatureFinder(
|
||||
moduleDescriptor, KonanManglerDesc,
|
||||
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 {
|
||||
if (idSig.isPubliclyVisible) {
|
||||
@@ -170,9 +594,233 @@ internal class KonanIrLinker(
|
||||
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) {
|
||||
init {
|
||||
assert(moduleDescriptor.isForwardDeclarationModule)
|
||||
require(moduleDescriptor.isForwardDeclarationModule)
|
||||
}
|
||||
|
||||
private val declaredDeclaration = mutableMapOf<IdSignature, IrClass>()
|
||||
@@ -190,10 +838,10 @@ internal class KonanIrLinker(
|
||||
override fun contains(idSig: IdSignature): Boolean = idSig.isForwardDeclarationSignature()
|
||||
|
||||
private fun resolveDescriptor(idSig: IdSignature): ClassDescriptor =
|
||||
with(idSig as IdSignature.CommonSignature) {
|
||||
val classId = ClassId(packageFqName(), FqName(declarationFqName), false)
|
||||
moduleDescriptor.findClassAcrossModuleDependencies(classId) ?: error("No declaration found with $idSig")
|
||||
}
|
||||
with(idSig as IdSignature.CommonSignature) {
|
||||
val classId = ClassId(packageFqName(), FqName(declarationFqName), false)
|
||||
moduleDescriptor.findClassAcrossModuleDependencies(classId) ?: error("No declaration found with $idSig")
|
||||
}
|
||||
|
||||
private fun buildForwardDeclarationStub(descriptor: ClassDescriptor): IrClass {
|
||||
return stubGenerator.generateClassStub(descriptor).also {
|
||||
@@ -202,7 +850,9 @@ internal class KonanIrLinker(
|
||||
}
|
||||
|
||||
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 actualModule = descriptor.module
|
||||
if (actualModule !== moduleDescriptor) {
|
||||
|
||||
Reference in New Issue
Block a user