[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.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()
|
||||
|
||||
+12
@@ -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()
|
||||
|
||||
+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
|
||||
|
||||
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))
|
||||
|
||||
}
|
||||
+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.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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user