[Linker] Extend KotlinIrLinker infrastructure to support libraries that
doesn't contain IR. Add IrProviderForInteropStubs for ir-less interop KLIBs.
This commit is contained in:
committed by
Sergey Bogolepov
parent
d2277148fb
commit
ad7bf0853d
+3
-1
@@ -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.common.serialization.metadata.KlibMetadataMonolithicSerializer
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.isForwardDeclarationModule
|
import org.jetbrains.kotlin.backend.konan.descriptors.isForwardDeclarationModule
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.konanLibrary
|
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.ir.KonanSymbols
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||||
import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier
|
import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier
|
||||||
@@ -179,9 +180,10 @@ internal val psiToIrPhase = konanUnitPhase(
|
|||||||
|
|
||||||
val functionIrClassFactory = BuiltInFictitiousFunctionIrClassFactory(
|
val functionIrClassFactory = BuiltInFictitiousFunctionIrClassFactory(
|
||||||
symbolTable, generatorContext.irBuiltIns, reflectionTypes)
|
symbolTable, generatorContext.irBuiltIns, reflectionTypes)
|
||||||
|
val irProviderForInteropStubs = IrProviderForInteropStubs()
|
||||||
val symbols = KonanSymbols(this, symbolTable, symbolTable.lazyWrapper, functionIrClassFactory)
|
val symbols = KonanSymbols(this, symbolTable, symbolTable.lazyWrapper, functionIrClassFactory)
|
||||||
val module = translator.generateModuleFragment(generatorContext, environment.getSourceFiles(),
|
val module = translator.generateModuleFragment(generatorContext, environment.getSourceFiles(),
|
||||||
deserializer, listOf(functionIrClassFactory))
|
deserializer, listOf(irProviderForInteropStubs, functionIrClassFactory))
|
||||||
|
|
||||||
if (this.stdlibModule in modulesWithoutDCE) {
|
if (this.stdlibModule in modulesWithoutDCE) {
|
||||||
functionIrClassFactory.buildAllClasses()
|
functionIrClassFactory.buildAllClasses()
|
||||||
|
|||||||
+12
@@ -6,6 +6,11 @@
|
|||||||
package org.jetbrains.kotlin.backend.konan.descriptors
|
package org.jetbrains.kotlin.backend.konan.descriptors
|
||||||
|
|
||||||
import org.jetbrains.kotlin.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.name.Name
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
|
import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
|
||||||
|
|
||||||
@@ -47,3 +52,10 @@ fun DeclarationDescriptor.findTopLevelDescriptor(): DeclarationDescriptor {
|
|||||||
|
|
||||||
val ModuleDescriptor.isForwardDeclarationModule get() =
|
val ModuleDescriptor.isForwardDeclarationModule get() =
|
||||||
name == Name.special("<forward declarations>")
|
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()
|
||||||
|
|||||||
+83
@@ -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
|
||||||
|
)
|
||||||
|
}
|
||||||
+25
-11
@@ -1,18 +1,32 @@
|
|||||||
package org.jetbrains.kotlin.backend.konan.serialization
|
package org.jetbrains.kotlin.backend.konan.serialization
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.LoggingContext
|
import org.jetbrains.kotlin.backend.common.LoggingContext
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.IrModuleSerializer
|
import org.jetbrains.kotlin.backend.common.serialization.*
|
||||||
import org.jetbrains.kotlin.backend.konan.RuntimeNames
|
import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.KonanMangler
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
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.ir.declarations.IrFile
|
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.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(
|
class KonanIrModuleSerializer(
|
||||||
logger: LoggingContext,
|
logger: LoggingContext,
|
||||||
@@ -24,6 +38,6 @@ class KonanIrModuleSerializer(
|
|||||||
private val globalDeclarationTable = KonanGlobalDeclarationTable(irBuiltIns)
|
private val globalDeclarationTable = KonanGlobalDeclarationTable(irBuiltIns)
|
||||||
|
|
||||||
override fun createSerializerForFile(file: IrFile): KonanIrFileSerializer =
|
override fun createSerializerForFile(file: IrFile): KonanIrFileSerializer =
|
||||||
KonanIrFileSerializer(logger, DeclarationTable(descriptorTable, globalDeclarationTable, 0))
|
KonanIrFileSerializer(logger, KonanDeclarationTable(descriptorTable, globalDeclarationTable, 0))
|
||||||
|
|
||||||
}
|
}
|
||||||
+9
-1
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.backend.konan.serialization
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.LoggingContext
|
import org.jetbrains.kotlin.backend.common.LoggingContext
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.*
|
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.descriptors.konanLibrary
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.KonanMangler
|
import org.jetbrains.kotlin.backend.konan.llvm.KonanMangler
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
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.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
|
|
||||||
class KonanIrLinker(
|
class KonanIrLinker(
|
||||||
currentModule: ModuleDescriptor,
|
currentModule: ModuleDescriptor,
|
||||||
@@ -58,7 +60,7 @@ class KonanIrLinker(
|
|||||||
moduleDescriptor.konanLibrary!!.file(fileIndex)
|
moduleDescriptor.konanLibrary!!.file(fileIndex)
|
||||||
|
|
||||||
override fun readFileCount(moduleDescriptor: ModuleDescriptor) =
|
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
|
private val ModuleDescriptor.userName get() = konanLibrary!!.libraryFile.absolutePath
|
||||||
|
|
||||||
@@ -68,6 +70,12 @@ class KonanIrLinker(
|
|||||||
return globalDeserializationState
|
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 {
|
val modules: Map<String, IrModuleFragment> get() = mutableMapOf<String, IrModuleFragment>().apply {
|
||||||
deserializersForModules.filter { !it.key.isForwardDeclarationModule }.forEach {
|
deserializersForModules.filter { !it.key.isForwardDeclarationModule }.forEach {
|
||||||
this.put(it.key.konanLibrary!!.libraryName, it.value.module)
|
this.put(it.key.konanLibrary!!.libraryName, it.value.module)
|
||||||
|
|||||||
@@ -3701,6 +3701,29 @@ task library_mismatch(type: KonanDriverTest) {
|
|||||||
goldValue = isWindows() ? messages.replaceAll('\\/', '\\\\') : messages
|
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 target = ext.platformManager.targetByName(project.testTarget ?: 'host')
|
||||||
def targetName = target.name
|
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_EXPORT_FORWARD_DECLARATIONS = "exportForwardDeclarations"
|
||||||
const val KLIB_PROPERTY_INCLUDED_HEADERS = "includedHeaders"
|
const val KLIB_PROPERTY_INCLUDED_HEADERS = "includedHeaders"
|
||||||
|
|
||||||
|
const val KLIB_INTEROP_IR_PROVIDER_IDENTIFIER = "kotlin.native.cinterop"
|
||||||
|
|
||||||
interface TargetedLibrary {
|
interface TargetedLibrary {
|
||||||
val targetList: List<String>
|
val targetList: List<String>
|
||||||
val includedPaths: List<String>
|
val includedPaths: List<String>
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ internal class KonanLibraryProperResolver(
|
|||||||
localKonanDir,
|
localKonanDir,
|
||||||
skipCurrentDir,
|
skipCurrentDir,
|
||||||
logger,
|
logger,
|
||||||
emptyList()
|
listOf(KLIB_INTEROP_IR_PROVIDER_IDENTIFIER)
|
||||||
), SearchPathResolverWithTarget<KonanLibrary>
|
), SearchPathResolverWithTarget<KonanLibrary>
|
||||||
{
|
{
|
||||||
override fun libraryBuilder(file: File, isDefault: Boolean) = createKonanLibrary(file, target, isDefault)
|
override fun libraryBuilder(file: File, isDefault: Boolean) = createKonanLibrary(file, target, isDefault)
|
||||||
|
|||||||
Reference in New Issue
Block a user