[Linker] Extend KotlinIrLinker infrastructure to support libraries that

doesn't contain IR.

Add IrProviderForInteropStubs for ir-less interop KLIBs.
This commit is contained in:
Sergey Bogolepov
2019-10-29 11:55:59 +07:00
committed by Sergey Bogolepov
parent d2277148fb
commit ad7bf0853d
11 changed files with 160 additions and 14 deletions
@@ -7,6 +7,7 @@ import org.jetbrains.kotlin.backend.common.serialization.DescriptorTable
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMonolithicSerializer
import org.jetbrains.kotlin.backend.konan.descriptors.isForwardDeclarationModule
import org.jetbrains.kotlin.backend.konan.descriptors.konanLibrary
import org.jetbrains.kotlin.backend.konan.ir.IrProviderForInteropStubs
import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier
@@ -179,9 +180,10 @@ internal val psiToIrPhase = konanUnitPhase(
val functionIrClassFactory = BuiltInFictitiousFunctionIrClassFactory(
symbolTable, generatorContext.irBuiltIns, reflectionTypes)
val irProviderForInteropStubs = IrProviderForInteropStubs()
val symbols = KonanSymbols(this, symbolTable, symbolTable.lazyWrapper, functionIrClassFactory)
val module = translator.generateModuleFragment(generatorContext, environment.getSourceFiles(),
deserializer, listOf(functionIrClassFactory))
deserializer, listOf(irProviderForInteropStubs, functionIrClassFactory))
if (this.stdlibModule in modulesWithoutDCE) {
functionIrClassFactory.buildAllClasses()
@@ -6,6 +6,11 @@
package org.jetbrains.kotlin.backend.konan.descriptors
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.konan.DeserializedKlibModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.klibModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.kotlinLibrary
import org.jetbrains.kotlin.konan.library.KLIB_INTEROP_IR_PROVIDER_IDENTIFIER
import org.jetbrains.kotlin.library.BaseKotlinLibrary
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
@@ -47,3 +52,10 @@ fun DeclarationDescriptor.findTopLevelDescriptor(): DeclarationDescriptor {
val ModuleDescriptor.isForwardDeclarationModule get() =
name == Name.special("<forward declarations>")
fun BaseKotlinLibrary.isInteropLibrary() =
manifestProperties["ir_provider"] == KLIB_INTEROP_IR_PROVIDER_IDENTIFIER
fun ModuleDescriptor.isFromInteropLibrary() =
if (klibModuleOrigin !is DeserializedKlibModuleOrigin) false
else kotlinLibrary.isInteropLibrary()
@@ -0,0 +1,83 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.backend.konan.ir
import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyDeclarationBase
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyFunction
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyProperty
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyTypeAlias
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeAliasSymbol
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.resolve.descriptorUtil.module
/**
* Generates external IR declarations for descriptors from interop libraries.
*/
class IrProviderForInteropStubs : LazyIrProvider {
override lateinit var declarationStubGenerator: DeclarationStubGenerator
override fun getDeclaration(symbol: IrSymbol): IrLazyDeclarationBase? =
if (symbol.descriptor.module.isFromInteropLibrary()) {
provideIrDeclaration(symbol)
} else {
null
}
private fun provideIrDeclaration(symbol: IrSymbol): IrLazyDeclarationBase = when (symbol) {
is IrSimpleFunctionSymbol -> provideIrFunction(symbol)
is IrPropertySymbol -> provideIrProperty(symbol)
is IrTypeAliasSymbol -> provideIrTypeAlias(symbol)
else -> error("Unsupported interop declaration: symbol=$symbol, descriptor=${symbol.descriptor}")
}
private fun provideIrFunction(symbol: IrSimpleFunctionSymbol): IrLazyFunction =
declarationStubGenerator.symbolTable.declareSimpleFunction(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB,
symbol.descriptor, this::createFunctionDeclaration
) as IrLazyFunction
private fun createFunctionDeclaration(symbol: IrSimpleFunctionSymbol) =
IrLazyFunction(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB,
symbol, declarationStubGenerator, declarationStubGenerator.typeTranslator
)
private fun provideIrProperty(symbol: IrPropertySymbol): IrLazyProperty =
declarationStubGenerator.symbolTable.declareProperty(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB,
symbol.descriptor, propertyFactory = this::createPropertyDeclaration
) as IrLazyProperty
private fun createPropertyDeclaration(symbol: IrPropertySymbol) =
IrLazyProperty(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB,
symbol, declarationStubGenerator, declarationStubGenerator.typeTranslator, null
)
private fun provideIrTypeAlias(symbol: IrTypeAliasSymbol): IrLazyTypeAlias =
declarationStubGenerator.symbolTable.declareTypeAlias(
symbol.descriptor, this::createTypeAlias
) as IrLazyTypeAlias
private fun createTypeAlias(symbol: IrTypeAliasSymbol): IrLazyTypeAlias =
IrLazyTypeAlias(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB,
symbol, symbol.descriptor.name,
symbol.descriptor.visibility, symbol.descriptor.isActual,
declarationStubGenerator, declarationStubGenerator.typeTranslator
)
}
@@ -1,18 +1,32 @@
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.serialization.IrModuleSerializer
import org.jetbrains.kotlin.backend.konan.RuntimeNames
import org.jetbrains.kotlin.backend.konan.llvm.KonanMangler
import org.jetbrains.kotlin.backend.common.serialization.DeclarationTable
import org.jetbrains.kotlin.backend.common.serialization.DescriptorTable
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsGlobalDeclarationTable
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrFileSerializer
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.backend.common.serialization.*
import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.resolve.descriptorUtil.module
private class KonanDeclarationTable(
descriptorTable: DescriptorTable,
globalDeclarationTable: GlobalDeclarationTable,
startIndex: Long
) : DeclarationTable(descriptorTable, globalDeclarationTable, startIndex),
DescriptorUniqIdAware by DeserializedDescriptorUniqIdAware {
/**
* It is incorrect to compute UniqId for declarations from metadata-based libraries.
* Instead we should get precomputed value from metadata.
*/
override fun tryComputeBackendSpecificUniqId(declaration: IrDeclaration): UniqId? {
return if (declaration.descriptor.module.isFromInteropLibrary()) {
UniqId(declaration.descriptor.getUniqId() ?: error("No uniq id found for ${declaration.descriptor}"))
} else {
null
}
}
}
class KonanIrModuleSerializer(
logger: LoggingContext,
@@ -24,6 +38,6 @@ class KonanIrModuleSerializer(
private val globalDeclarationTable = KonanGlobalDeclarationTable(irBuiltIns)
override fun createSerializerForFile(file: IrFile): KonanIrFileSerializer =
KonanIrFileSerializer(logger, DeclarationTable(descriptorTable, globalDeclarationTable, 0))
KonanIrFileSerializer(logger, KonanDeclarationTable(descriptorTable, globalDeclarationTable, 0))
}
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.serialization.*
import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary
import org.jetbrains.kotlin.backend.konan.descriptors.konanLibrary
import org.jetbrains.kotlin.backend.konan.llvm.KonanMangler
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
@@ -25,6 +26,7 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.resolve.descriptorUtil.module
class KonanIrLinker(
currentModule: ModuleDescriptor,
@@ -58,7 +60,7 @@ class KonanIrLinker(
moduleDescriptor.konanLibrary!!.file(fileIndex)
override fun readFileCount(moduleDescriptor: ModuleDescriptor) =
moduleDescriptor.run { if (isForwardDeclarationModule) 0 else konanLibrary!!.fileCount() }
moduleDescriptor.run { if (isForwardDeclarationModule || !shouldBeDeserialized()) 0 else konanLibrary!!.fileCount() }
private val ModuleDescriptor.userName get() = konanLibrary!!.libraryFile.absolutePath
@@ -68,6 +70,12 @@ class KonanIrLinker(
return globalDeserializationState
}
/**
* If declaration is from interop library then IR for it is generated by IrProviderForInteropStubs.
*/
override fun DeclarationDescriptor.shouldBeDeserialized(): Boolean =
!module.isFromInteropLibrary()
val modules: Map<String, IrModuleFragment> get() = mutableMapOf<String, IrModuleFragment>().apply {
deserializersForModules.filter { !it.key.isForwardDeclarationModule }.forEach {
this.put(it.key.konanLibrary!!.libraryName, it.value.module)
+23
View File
@@ -3701,6 +3701,29 @@ task library_mismatch(type: KonanDriverTest) {
goldValue = isWindows() ? messages.replaceAll('\\/', '\\\\') : messages
}
task library_ir_provider_mismatch(type: KonanDriverTest) {
def dir = buildDir.absolutePath
def lib = "$projectDir/link/ir_providers/library/empty.kt"
def invalidManifest = "$projectDir/link/ir_providers/library/manifest.properties"
def currentTarget = project.target.name
doBefore {
def konancScript = isWindows() ? "konanc.bat" : "konanc"
def konanc = "$dist/bin/$konancScript"
"$konanc $lib -p library -o $dir/supported_ir_provider/empty -target $currentTarget".execute().waitFor()
"$konanc $lib -p library -o $dir/unsupported_ir_provider/empty -manifest $invalidManifest -target $currentTarget".execute().waitFor()
}
source = "link/ir_providers/hello.kt"
flags = ['-target', currentTarget, '-l', 'empty', '-r', "$dir/unsupported_ir_provider", '-r', "$dir/supported_ir_provider"]
compilerMessages = true
def messages =
"warning: skipping $dir/unsupported_ir_provider/empty.klib. The library requires unknown IR provider UNSUPPORTED.\n" +
"hello\n"
goldValue = isWindows() ? messages.replaceAll('\\/', '\\\\') : messages
}
def target = ext.platformManager.targetByName(project.testTarget ?: 'host')
def targetName = target.name
@@ -0,0 +1 @@
fun main() = println("hello")
@@ -0,0 +1 @@
ir_provider=UNSUPPORTED
@@ -10,6 +10,8 @@ const val KLIB_PROPERTY_INTEROP = "interop"
const val KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS = "exportForwardDeclarations"
const val KLIB_PROPERTY_INCLUDED_HEADERS = "includedHeaders"
const val KLIB_INTEROP_IR_PROVIDER_IDENTIFIER = "kotlin.native.cinterop"
interface TargetedLibrary {
val targetList: List<String>
val includedPaths: List<String>
@@ -81,7 +81,7 @@ internal class KonanLibraryProperResolver(
localKonanDir,
skipCurrentDir,
logger,
emptyList()
listOf(KLIB_INTEROP_IR_PROVIDER_IDENTIFIER)
), SearchPathResolverWithTarget<KonanLibrary>
{
override fun libraryBuilder(file: File, isDefault: Boolean) = createKonanLibrary(file, target, isDefault)