Fix K/N for new linker

(cherry picked from commit ea31937c010da2e0d3a1fb5d8b49625ffc31115e)
This commit is contained in:
Roman Artemev
2020-01-29 17:35:43 +03:00
committed by Vasily Levchenko
parent 1f4273c5ec
commit 735013cc42
15 changed files with 323 additions and 259 deletions
@@ -58,7 +58,7 @@ import org.jetbrains.kotlin.library.SerializedIrModule
* Offset for synthetic elements created by lowerings and not attributable to other places in the source code.
*/
internal class SpecialDeclarationsFactory(val context: Context) : KotlinMangler by KonanManglerForBE {
internal class SpecialDeclarationsFactory(val context: Context) {
private val enumSpecialDeclarationsFactory by lazy { EnumSpecialDeclarationsFactory(context) }
private val outerThisFields = mutableMapOf<ClassDescriptor, IrField>()
private val bridgesDescriptors = mutableMapOf<Pair<IrSimpleFunction, BridgeDirections>, IrSimpleFunction>()
@@ -259,6 +259,7 @@ fun ConstructorDescriptor.objCConstructorIsDesignated(): Boolean {
val IrConstructor.isObjCConstructor get() = this.annotations.hasAnnotation(objCConstructorFqName)
val ConstructorDescriptor.isObjCConstructor get() = this.annotations.hasAnnotation(objCConstructorFqName)
// TODO-DCE-OBJC-INIT: Selector should be preserved by DCE.
fun IrConstructor.getObjCInitMethod(): IrSimpleFunction? {
@@ -270,9 +271,20 @@ fun IrConstructor.getObjCInitMethod(): IrSimpleFunction? {
}
}
fun ConstructorDescriptor.getObjCInitMethod(): FunctionDescriptor? {
return this.annotations.findAnnotation(objCConstructorFqName)?.let {
val initSelector = it.getAnnotationStringValue("initSelector")
this.constructedClass.unsubstitutedMemberScope.getContributedDescriptors().asSequence()
.filterIsInstance<FunctionDescriptor>()
.single { it.getExternalObjCMethodInfo()?.selector == initSelector }
}
}
val IrFunction.hasObjCFactoryAnnotation get() = this.annotations.hasAnnotation(objCFactoryFqName)
val FunctionDescriptor.hasObjCFactoryAnnotation get() = this.annotations.hasAnnotation(objCFactoryFqName)
val IrFunction.hasObjCMethodAnnotation get() = this.annotations.hasAnnotation(objCMethodFqName)
val FunctionDescriptor.hasObjCMethodAnnotation get() = this.annotations.hasAnnotation(objCMethodFqName)
fun FunctionDescriptor.getObjCFactoryInitMethodInfo(): ObjCMethodInfo? {
val factoryAnnotation = this.annotations.findAnnotation(objCFactoryFqName) ?: return null
@@ -4,7 +4,8 @@ import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.common.phaser.*
import org.jetbrains.kotlin.backend.common.serialization.DescriptorTable
import org.jetbrains.kotlin.backend.common.serialization.mangle.ManglerChecker
import org.jetbrains.kotlin.backend.common.serialization.mangle.descriptor.Ir2DescriptorManglerAdapter
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMonolithicSerializer
import org.jetbrains.kotlin.backend.konan.descriptors.isForwardDeclarationModule
import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary
@@ -29,6 +30,7 @@ import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.addChild
import org.jetbrains.kotlin.ir.util.addFile
import org.jetbrains.kotlin.ir.util.file
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
@@ -107,7 +109,7 @@ private var Context.symbolTable: SymbolTable? by Context.nullValue()
internal val createSymbolTablePhase = konanUnitPhase(
op = {
this.symbolTable = SymbolTable()
this.symbolTable = SymbolTable(KonanIdSignaturer(KonanManglerDesc))
},
name = "CreateSymbolTable",
description = "Create SymbolTable"
@@ -143,7 +145,7 @@ internal val psiToIrPhase = konanUnitPhase(
val symbolTable = symbolTable!!
val translator = Psi2IrTranslator(config.configuration.languageVersionSettings,
Psi2IrConfiguration(false))
Psi2IrConfiguration(false), KonanIdSignaturer(KonanManglerDesc))
val generatorContext = translator.createGeneratorContext(moduleDescriptor, bindingContext, symbolTable)
translator.addPostprocessingStep { module ->
@@ -240,6 +242,12 @@ internal val psiToIrPhase = konanUnitPhase(
if (this.stdlibModule in modulesWithoutDCE) {
functionIrClassFactory.buildAllClasses()
}
modulesWithoutDCE
.filter(ModuleDescriptor::isFromInteropLibrary)
.forEach(irProviderForCEnumsAndCStructs::buildAllEnumsAndStructsFrom)
module.acceptVoid(ManglerChecker(KonanManglerIr, Ir2DescriptorManglerAdapter(KonanManglerDesc)))
irModule = module
irModules = deserializer.modules.filterValues { llvmModuleSpecification.containsModule(it) }
ir.symbols = symbols
@@ -279,18 +287,17 @@ internal val copyDefaultValuesToActualPhase = konanUnitPhase(
internal val serializerPhase = konanUnitPhase(
op = {
val mppKlibs = config.configuration.get(CommonConfigurationKeys.KLIB_MPP)?:false
val descriptorTable = DescriptorTable.createDefault()
serializedIr = irModule?.let { ir ->
KonanIrModuleSerializer(
this, ir.irBuiltins, descriptorTable, expectDescriptorToSymbol, skipExpects = !mppKlibs
this, ir.irBuiltins, expectDescriptorToSymbol, skipExpects = !mppKlibs
).serializedIrModule(ir)
}
val serializer = KlibMetadataMonolithicSerializer(
this.config.configuration.languageVersionSettings,
config.configuration.get(CommonConfigurationKeys.METADATA_VERSION)!!,
descriptorTable, !mppKlibs)
!mppKlibs)
serializedMetadata = serializer.serializeModule(moduleDescriptor)
},
name = "Serializer",
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.backend.konan.isObjCClass
import org.jetbrains.kotlin.backend.konan.llvm.longName
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.IrConst
@@ -20,6 +21,9 @@ import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.resolve.annotations.argumentValue
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
/**
* List of all implemented interfaces (including those which implemented by a super class)
@@ -267,6 +271,10 @@ fun IrConstructorCall.getAnnotationStringValue(name: String): String {
return (getValueArgument(parameter.index) as IrConst<String>).value
}
fun AnnotationDescriptor.getAnnotationStringValue(name: String): String {
return argumentValue(name)?.safeAs<StringValue>()?.value ?: error("Expected value $name at annotation $this")
}
fun <T> IrConstructorCall.getAnnotationValueOrNull(name: String): T? {
val parameter = symbol.owner.valueParameters.atMostOne { it.name.asString() == name }
return parameter?.let { getValueArgument(it.index)?.let { (it as IrConst<T>).value } }
@@ -71,7 +71,8 @@ internal class IrProviderForCEnumAndCStructStubs(
}
fun canHandleSymbol(symbol: IrSymbol): Boolean {
if (!symbol.descriptor.module.isFromInteropLibrary()) return false
if (!symbol.isPublicApi) return false
if (symbol.signature.run { !IdSignature.Flags.IS_NATIVE_INTEROP_LIBRARY.test() }) return false
return symbol.findCEnumDescriptor(interopBuiltIns) != null
|| symbol.findCStructDescriptor(interopBuiltIns) != null
}
@@ -33,7 +33,8 @@ class IrProviderForInteropStubs(
// So for now we relate on correct behavior of subsequent providers.
symbol.isBound -> null
isSpecialInteropCase(symbol) -> null
symbol.descriptor.module.isFromInteropLibrary() -> provideIrDeclaration(symbol)
symbol.isPublicApi && symbol.signature.run { IdSignature.Flags.IS_NATIVE_INTEROP_LIBRARY.test() } ->
provideIrDeclaration(symbol)
else -> null
}
@@ -6,21 +6,21 @@
package org.jetbrains.kotlin.backend.konan.llvm
import llvm.LLVMTypeRef
import org.jetbrains.kotlin.backend.common.serialization.KotlinManglerImpl
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.common.serialization.mangle.MangleConstant
import org.jetbrains.kotlin.backend.common.serialization.mangle.SpecialDeclarationType
import org.jetbrains.kotlin.backend.konan.RuntimeNames
import org.jetbrains.kotlin.backend.konan.descriptors.externalSymbolOrThrow
import org.jetbrains.kotlin.backend.konan.descriptors.getAnnotationStringValue
import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract
import org.jetbrains.kotlin.backend.konan.ir.allParameters
import org.jetbrains.kotlin.backend.konan.getObjCMethodInfo
import org.jetbrains.kotlin.backend.konan.isObjCClassMethod
import org.jetbrains.kotlin.backend.konan.ir.isUnit
import org.jetbrains.kotlin.backend.konan.llvm.KonanMangler.isExported
import org.jetbrains.kotlin.backend.konan.isExternalObjCClass
import org.jetbrains.kotlin.backend.konan.serialization.KonanManglerIr
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.backend.konan.isInlinedNative
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.findAnnotation
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
import org.jetbrains.kotlin.ir.util.isSuspend
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.library.uniqueName
@@ -29,106 +29,52 @@ import org.jetbrains.kotlin.library.uniqueName
// TODO: revise the naming scheme to ensure it produces unique names.
// TODO: do not serialize descriptors of non-exported declarations.
abstract class AbstractKonanMangler : KotlinManglerImpl() {
object KonanBinaryInterface {
private val mangler = KonanManglerIr
private val exportChecker = mangler.getExportChecker()
override val IrType.isInlined
get() = this.isInlinedNative()
val IrFunction.functionName: String get() = mangler.run { signatureString }
/**
* Defines whether the declaration is exported, i.e. visible from other modules.
*
* Exported declarations must have predictable and stable ABI
* that doesn't depend on any internal transformations (e.g. IR lowering),
* and so should be computable from the descriptor itself without checking a backend state.
*/
override fun IrDeclaration.isPlatformSpecificExported(): Boolean {
// TODO: revise
if (annotations.hasAnnotation(RuntimeNames.symbolNameAnnotation)) {
// Treat any `@SymbolName` declaration as exported.
return true
}
if (annotations.hasAnnotation(RuntimeNames.exportForCppRuntime)) {
// Treat any `@ExportForCppRuntime` declaration as exported.
return true
}
if (annotations.hasAnnotation(RuntimeNames.cnameAnnotation)) {
// Treat `@CName` declaration as exported.
return true
}
if (annotations.hasAnnotation(RuntimeNames.exportForCompilerAnnotation)) {
return true
}
return false
val IrFunction.symbolName: String get() = funSymbolNameImpl()
val IrField.symbolName: String get() =
withPrefix(MangleConstant.FIELD_PREFIX, fieldSymbolNameImpl())
val IrClass.typeInfoSymbolName: String get() =
withPrefix(MangleConstant.CLASS_PREFIX, typeInfoSymbolNameImpl())
fun isExported(declaration: IrDeclaration) = exportChecker.run {
check(declaration, SpecialDeclarationType.REGULAR) || declaration.isPlatformSpecificExported()
}
override fun IrFunction.valueParamsPart(typeParameterNamer: (IrTypeParameter) -> String): String {
return this.valueParameters.map {
private fun withPrefix(prefix: String, mangle: String) = "$prefix:$mangle"
// TODO: there are clashes originating from ObjectiveC interop.
// kotlinx.cinterop.ObjCClassOf<T>.create(format: kotlin.String): T defined in platform.Foundation in file Foundation.kt
// and
// kotlinx.cinterop.ObjCClassOf<T>.create(string: kotlin.String): T defined in platform.Foundation in file Foundation.kt
private fun IrFunction.funSymbolNameImpl(): String {
if (!isExported(this)) {
throw AssertionError(render())
}
val argName =
if (this.hasObjCMethodAnnotation || this.hasObjCFactoryAnnotation || this.isObjCClassMethod()) "${it.name}:" else ""
"$argName${typeToHashString(it.type, typeParameterNamer)}${if (it.isVararg) "_VarArg" else ""}"
}.joinToString(";")
if (isExternal) {
this.externalSymbolOrThrow()?.let {
return it
}
}
this.annotations.findAnnotation(RuntimeNames.exportForCppRuntime)?.let {
val name = it.getAnnotationStringValue() ?: this.name.asString()
return name // no wrapping currently required
}
return withPrefix(MangleConstant.FUN_PREFIX, mangler.run { mangleString })
}
override val IrFunction.platformSpecificFunctionName: String?
get() {
(if (this is IrConstructor && this.isObjCConstructor) this.getObjCInitMethod() else this)?.getObjCMethodInfo()
?.let {
return buildString {
if (extensionReceiverParameter != null) {
append(extensionReceiverParameter!!.type.getClass()!!.name)
append(".")
}
append("objc:")
append(it.selector)
if (this@platformSpecificFunctionName is IrConstructor && this@platformSpecificFunctionName.isObjCConstructor) append("#Constructor")
if ((this@platformSpecificFunctionName as? IrSimpleFunction)?.correspondingPropertySymbol != null) {
append("#Accessor")
}
}
}
return null
private fun IrField.fieldSymbolNameImpl(): String {
val containingDeclarationPart = parent.fqNameForIrSerialization.let {
if (it.isRoot) "" else "$it."
}
return "$containingDeclarationPart$name"
}
internal val IrFunction.symbolName: String
get() {
if (!this.isExported()) {
throw AssertionError(this.descriptor.toString())
}
if (isExternal) {
this.externalSymbolOrThrow()?.let {
return it
}
}
this.annotations.findAnnotation(RuntimeNames.exportForCppRuntime)?.let {
val name = it.getAnnotationStringValue() ?: this.name.asString()
return name // no wrapping currently required
}
val parent = this.parent
val containingDeclarationPart = parent.fqNameForIrSerialization.let {
if (it.isRoot) "" else "$it."
}
return "kfun:$containingDeclarationPart$functionName"
}
}
object KonanMangler : AbstractKonanMangler()
object KonanManglerForBE : AbstractKonanMangler() {
override fun mangleTypeParameter(typeParameter: IrTypeParameter, typeParameterNamer: (IrTypeParameter) -> String): String =
typeParameter.name.asString()
private fun IrClass.typeInfoSymbolNameImpl(): String {
return this.fqNameForIrSerialization.toString()
}
}
internal val IrClass.writableTypeInfoSymbolName: String
@@ -146,15 +92,15 @@ internal val IrClass.objectInstanceGetterSymbolName: String
return "kobjget:$fqNameForIrSerialization"
}
val IrFunction.functionName get() = with(KonanManglerForBE) { functionName }
val IrFunction.functionName get() = with(KonanBinaryInterface) { functionName }
val IrFunction.symbolName get() = with(KonanManglerForBE) { symbolName }
val IrFunction.symbolName get() = with(KonanBinaryInterface) { symbolName }
val IrField.symbolName get() = with(KonanManglerForBE) { symbolName }
val IrField.symbolName get() = with(KonanBinaryInterface) { symbolName }
val IrClass.typeInfoSymbolName get() = with(KonanManglerForBE) { typeInfoSymbolName }
val IrClass.typeInfoSymbolName get() = with(KonanBinaryInterface) { typeInfoSymbolName }
fun IrDeclaration.isExported() = with(KonanManglerForBE) { isExported() }
fun IrDeclaration.isExported() = KonanBinaryInterface.isExported(this)
// TODO: bring here dependencies of this method?
internal fun RuntimeAware.getLlvmFunctionType(function: IrFunction): LLVMTypeRef {
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract
import org.jetbrains.kotlin.backend.konan.descriptors.target
import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.llvm.KonanMangler.symbolName
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_BRIDGE_METHOD
import org.jetbrains.kotlin.backend.konan.lower.bridgeTarget
import org.jetbrains.kotlin.descriptors.Modality
@@ -1,12 +1,11 @@
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.common.serialization.GlobalDeclarationTable
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureSerializer
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
class KonanGlobalDeclarationTable(builtIns: IrBuiltIns) : GlobalDeclarationTable(KonanMangler) {
class KonanGlobalDeclarationTable(signatureSerializer: IdSignatureSerializer, builtIns: IrBuiltIns) : GlobalDeclarationTable(signatureSerializer, KonanManglerIr) {
init {
loadKnownBuiltins(builtIns)
}
@@ -1,15 +0,0 @@
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.common.serialization.*
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.util.KotlinMangler
import org.jetbrains.kotlin.ir.util.UniqId
class KonanDescriptorReferenceDeserializer(
currentModule: ModuleDescriptor,
mangler: KotlinMangler,
builtIns: IrBuiltIns,
resolvedForwardDeclarations: MutableMap<UniqId, UniqId>
): DescriptorReferenceDeserializer(currentModule, mangler, builtIns, resolvedForwardDeclarations),
DescriptorUniqIdAware by DeserializedDescriptorUniqIdAware
@@ -0,0 +1,8 @@
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor
import org.jetbrains.kotlin.ir.util.KotlinMangler
class KonanIdSignaturer(mangler: KotlinMangler.DescriptorMangler) : IdSignatureDescriptor(mangler) {
}
@@ -1,49 +1,23 @@
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.descriptors.propertyIfAccessor
import org.jetbrains.kotlin.backend.common.serialization.*
import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureSerializer
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.UniqId
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()) {
// Property accessor doesn't provide UniqId so we need to get it from the property itself.
UniqId(declaration.descriptor.propertyIfAccessor.getUniqId() ?: error("No uniq id found for ${declaration.descriptor}"))
} else {
null
}
}
}
class KonanIrModuleSerializer(
logger: LoggingContext,
irBuiltIns: IrBuiltIns,
private val descriptorTable: DescriptorTable,
private val expectDescriptorToSymbol: MutableMap<DeclarationDescriptor, IrSymbol>,
val skipExpects: Boolean
) : IrModuleSerializer<KonanIrFileSerializer>(logger) {
private val globalDeclarationTable = KonanGlobalDeclarationTable(irBuiltIns)
private val signaturer = IdSignatureSerializer(KonanManglerIr)
private val globalDeclarationTable = KonanGlobalDeclarationTable(signaturer, irBuiltIns)
override fun createSerializerForFile(file: IrFile): KonanIrFileSerializer =
KonanIrFileSerializer(logger, KonanDeclarationTable(descriptorTable, globalDeclarationTable, 0), expectDescriptorToSymbol, skipExpects = skipExpects)
KonanIrFileSerializer(logger, DeclarationTable(globalDeclarationTable), expectDescriptorToSymbol, skipExpects = skipExpects)
}
@@ -20,38 +20,43 @@ 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.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrFileSymbolImpl
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.ir.util.NaiveSourceBasedFileEntryImpl
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.UniqId
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
class KonanIrLinker(
currentModule: ModuleDescriptor,
private val currentModule: ModuleDescriptor,
logger: LoggingContext,
builtIns: IrBuiltIns,
symbolTable: SymbolTable,
forwardModuleDescriptor: ModuleDescriptor?,
private val forwardModuleDescriptor: ModuleDescriptor?,
exportedDependencies: List<ModuleDescriptor>
) : KotlinIrLinker(logger, builtIns, symbolTable, exportedDependencies, forwardModuleDescriptor, KonanMangler),
DescriptorUniqIdAware by DeserializedDescriptorUniqIdAware {
) : KotlinIrLinker(logger, builtIns, symbolTable, exportedDependencies, forwardModuleDescriptor) {
override val descriptorReferenceDeserializer =
KonanDescriptorReferenceDeserializer(currentModule, KonanMangler, builtIns, resolvedForwardDeclarations)
override fun reader(moduleDescriptor: ModuleDescriptor, fileIndex: Int, uniqId: UniqId) =
moduleDescriptor.konanLibrary!!.irDeclaration(uniqId.index, fileIndex)
override fun readSymbol(moduleDescriptor: ModuleDescriptor, fileIndex: Int, symbolIndex: Int) =
moduleDescriptor.konanLibrary!!.symbol(symbolIndex, fileIndex)
override fun reader(moduleDescriptor: ModuleDescriptor, fileIndex: Int, idSigIndex: Int) =
moduleDescriptor.konanLibrary!!.irDeclaration(idSigIndex, fileIndex)
override fun readType(moduleDescriptor: ModuleDescriptor, fileIndex: Int, typeIndex: Int) =
moduleDescriptor.konanLibrary!!.type(typeIndex, fileIndex)
override fun readSignature(moduleDescriptor: ModuleDescriptor, fileIndex: Int, signatureIndex: Int) =
moduleDescriptor.konanLibrary!!.signature(signatureIndex, fileIndex)
override fun readString(moduleDescriptor: ModuleDescriptor, fileIndex: Int, stringIndex: Int) =
moduleDescriptor.konanLibrary!!.string(stringIndex, fileIndex)
@@ -62,19 +67,65 @@ class KonanIrLinker(
moduleDescriptor.konanLibrary!!.file(fileIndex)
override fun readFileCount(moduleDescriptor: ModuleDescriptor) =
moduleDescriptor.run { if (isForwardDeclarationModule || !shouldBeDeserialized()) 0 else konanLibrary!!.fileCount() }
moduleDescriptor.run { if (this === forwardModuleDescriptor || moduleDescriptor.isFromInteropLibrary()) 0 else konanLibrary!!.fileCount() }
private val ModuleDescriptor.userName get() = konanLibrary!!.libraryFile.absolutePath
override fun handleNoModuleDeserializerFound(key: UniqId): DeserializationState<*> {
override fun handleNoModuleDeserializerFound(idSignature: IdSignature): DeserializationState<*> {
return globalDeserializationState
}
companion object {
private val C_NAMES_NAME = Name.identifier("cnames")
private val OBJC_NAMES_NAME = Name.identifier("objcnames")
}
override fun isSpecialPlatformSignature(idSig: IdSignature): Boolean = idSig.isForwardDeclarationSignature()
override fun postProcessPlatformSpecificDeclaration(idSig: IdSignature, descriptor: DeclarationDescriptor?, block: (IdSignature) -> Unit) {
if (descriptor == null) return
if (!idSig.isForwardDeclarationSignature()) return
val fqn = descriptor.fqNameSafe
if (!fqn.startsWith(C_NAMES_NAME) && !fqn.startsWith(OBJC_NAMES_NAME)) {
val signature = IdSignature.PublicSignature(fqn.parent(), FqName(fqn.shortName().asString()), null, 0)
block(signature)
}
}
override fun resolvePlatformDescriptor(idSig: IdSignature): DeclarationDescriptor? {
if (!idSig.isForwardDeclarationSignature()) return null
val fwdModule = forwardModuleDescriptor ?: error("Forward declaration module should not be null")
return with(idSig as IdSignature.PublicSignature) {
val classId = ClassId(packageFqn, classFqn, false)
fwdModule.findClassAcrossModuleDependencies(classId)
}
}
private fun IdSignature.isInteropSignature(): Boolean = IdSignature.Flags.IS_NATIVE_INTEROP_LIBRARY.test()
private fun IdSignature.isForwardDeclarationSignature(): Boolean {
if (isPublic) {
return packageFqName().run {
startsWith(C_NAMES_NAME) || startsWith(OBJC_NAMES_NAME)
}
}
return false
}
override fun createModuleDeserializer(moduleDescriptor: ModuleDescriptor, strategy: DeserializationStrategy): IrModuleDeserializer {
return KonanModuleDeserializer(moduleDescriptor, strategy)
}
private inner class KonanModuleDeserializer(moduleDescriptor: ModuleDescriptor, strategy: DeserializationStrategy):
IrModuleDeserializer(moduleDescriptor, strategy)
/**
* If declaration is from interop library then IR for it is generated by IrProviderForInteropStubs.
*/
override fun DeclarationDescriptor.shouldBeDeserialized(): Boolean =
!module.isFromInteropLibrary()
override fun IdSignature.shouldBeDeserialized(): Boolean = !isInteropSignature() && !isForwardDeclarationSignature()
val modules: Map<String, IrModuleFragment> get() = mutableMapOf<String, IrModuleFragment>().apply {
deserializersForModules.filter { !it.key.isForwardDeclarationModule }.forEach {
@@ -0,0 +1,148 @@
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.common.serialization.mangle.MangleMode
import org.jetbrains.kotlin.backend.common.serialization.mangle.descriptor.DescriptorBasedKotlinManglerImpl
import org.jetbrains.kotlin.backend.common.serialization.mangle.descriptor.DescriptorExportCheckerVisitor
import org.jetbrains.kotlin.backend.common.serialization.mangle.descriptor.DescriptorMangleComputer
import org.jetbrains.kotlin.backend.common.serialization.mangle.ir.IrBasedKotlinManglerImpl
import org.jetbrains.kotlin.backend.common.serialization.mangle.ir.IrExportCheckerVisitor
import org.jetbrains.kotlin.backend.common.serialization.mangle.ir.IrMangleComputer
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.util.hasAnnotation
abstract class AbstractKonanIrMangler : IrBasedKotlinManglerImpl() {
override fun getExportChecker(): IrExportCheckerVisitor = KonanIrExportChecker()
override fun getMangleComputer(mode: MangleMode): IrMangleComputer = KonanIrManglerComputer(StringBuilder(256), mode)
private class KonanIrExportChecker : IrExportCheckerVisitor() {
override fun IrDeclaration.isPlatformSpecificExported(): Boolean {
if (this is IrSimpleFunction) if (isFakeOverride) return false
// TODO: revise
if (annotations.hasAnnotation(RuntimeNames.symbolNameAnnotation)) {
// Treat any `@SymbolName` declaration as exported.
return true
}
if (annotations.hasAnnotation(RuntimeNames.exportForCppRuntime)) {
// Treat any `@ExportForCppRuntime` declaration as exported.
return true
}
if (annotations.hasAnnotation(RuntimeNames.cnameAnnotation)) {
// Treat `@CName` declaration as exported.
return true
}
if (annotations.hasAnnotation(RuntimeNames.exportForCompilerAnnotation)) {
return true
}
return false
}
}
private class KonanIrManglerComputer(builder: StringBuilder, mode: MangleMode) : IrMangleComputer(builder, mode) {
override fun copy(newMode: MangleMode): IrMangleComputer = KonanIrManglerComputer(builder, newMode)
override fun IrFunction.platformSpecificFunctionName(): String? {
(if (this is IrConstructor && this.isObjCConstructor) this.getObjCInitMethod() else this)?.getObjCMethodInfo()
?.let {
return buildString {
if (extensionReceiverParameter != null) {
append(extensionReceiverParameter!!.type.getClass()!!.name)
append(".")
}
append("objc:")
append(it.selector)
if (this@platformSpecificFunctionName is IrConstructor && this@platformSpecificFunctionName.isObjCConstructor) append("#Constructor")
if ((this@platformSpecificFunctionName as? IrSimpleFunction)?.correspondingPropertySymbol != null) {
append("#Accessor")
}
}
}
return null
}
override fun IrFunction.specialValueParamPrefix(param: IrValueParameter): String {
// TODO: there are clashes originating from ObjectiveC interop.
// kotlinx.cinterop.ObjCClassOf<T>.create(format: kotlin.String): T defined in platform.Foundation in file Foundation.kt
// and
// kotlinx.cinterop.ObjCClassOf<T>.create(string: kotlin.String): T defined in platform.Foundation in file Foundation.kt
return if (this.hasObjCMethodAnnotation || this.hasObjCFactoryAnnotation || this.isObjCClassMethod()) "${param.name}:" else ""
}
}
}
object KonanManglerIr : AbstractKonanIrMangler()
abstract class AbstractKonanDescriptorMangler : DescriptorBasedKotlinManglerImpl() {
override fun getExportChecker(): DescriptorExportCheckerVisitor = KonanDescriptorExportChecker()
override fun getMangleComputer(mode: MangleMode): DescriptorMangleComputer =
KonanDescriptorMangleComputer(StringBuilder(256), mode)
private class KonanDescriptorExportChecker : DescriptorExportCheckerVisitor() {
override fun DeclarationDescriptor.isPlatformSpecificExported(): Boolean {
if (this is SimpleFunctionDescriptor) {
if (kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) return false
}
// TODO: revise
if (annotations.hasAnnotation(RuntimeNames.symbolNameAnnotation)) {
// Treat any `@SymbolName` declaration as exported.
return true
}
if (annotations.hasAnnotation(RuntimeNames.exportForCppRuntime)) {
// Treat any `@ExportForCppRuntime` declaration as exported.
return true
}
if (annotations.hasAnnotation(RuntimeNames.cnameAnnotation)) {
// Treat `@CName` declaration as exported.
return true
}
if (annotations.hasAnnotation(RuntimeNames.exportForCompilerAnnotation)) {
return true
}
return false
}
}
private class KonanDescriptorMangleComputer(builder: StringBuilder, mode: MangleMode) : DescriptorMangleComputer(builder, mode) {
override fun copy(newMode: MangleMode): DescriptorMangleComputer = KonanDescriptorMangleComputer(builder, newMode)
override fun FunctionDescriptor.platformSpecificFunctionName(): String? {
(if (this is ConstructorDescriptor && this.isObjCConstructor) this.getObjCInitMethod() else this)?.getObjCMethodInfo()
?.let {
return buildString {
if (extensionReceiverParameter != null) {
append(extensionReceiverParameter!!.type.constructor.declarationDescriptor!!.name)
append(".")
}
append("objc:")
append(it.selector)
if (this@platformSpecificFunctionName is ConstructorDescriptor && this@platformSpecificFunctionName.isObjCConstructor) append("#Constructor")
if (this@platformSpecificFunctionName is PropertyAccessorDescriptor) {
append("#Accessor")
}
}
}
return null
}
override fun FunctionDescriptor.specialValueParamPrefix(param: ValueParameterDescriptor): String {
return if (this.hasObjCMethodAnnotation || this.hasObjCFactoryAnnotation || this.isObjCClassMethod()) "${param.name}:" else ""
}
}
}
object KonanManglerDesc : AbstractKonanDescriptorMangler()
@@ -1,75 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.build
import org.jetbrains.report.*
import org.jetbrains.report.json.*
data class Build(val buildNumber: String, val startTime: String, val finishTime: String, val branch: String,
val commits: String, val buildType: String, val failuresNumber: Int, val executionTime: String,
val compileTime: String, val codeSize: String, val bundleSize: String?) {
companion object: EntityFromJsonFactory<Build> {
override fun create(data: JsonElement): Build {
if (data is JsonObject) {
val buildNumber = elementToString(data.getRequiredField("buildNumber"), "buildNumber")
val startTime = elementToString(data.getRequiredField("startTime"), "startTime")
val finishTime = elementToString(data.getRequiredField("finishTime"), "finishTime")
val branch = elementToString(data.getRequiredField("branch"), "branch")
val commits = elementToString(data.getRequiredField("commits"), "commits")
val buildType = elementToString(data.getRequiredField("buildType"), "buildType")
val failuresNumber = elementToInt(data.getRequiredField("failuresNumber"), "failuresNumber")
val executionTime = elementToString(data.getRequiredField("executionTime"), "executionTime")
val compileTime = elementToString(data.getRequiredField("compileTime"), "compileTime")
val codeSize = elementToString(data.getRequiredField("codeSize"), "codeSize")
val bundleSize = elementToStringOrNull(data.getRequiredField("bundleSize"), "bundleSize")
return Build(buildNumber, startTime, finishTime, branch, commits, buildType, failuresNumber, executionTime,
compileTime, codeSize, bundleSize)
} else {
error("Top level entity is expected to be an object. Please, check origin files.")
}
}
}
private fun formatTime(time: String, targetZone: Int = 3): String {
val matchResult = "^\\d{8}T(\\d{2})(\\d{2})\\d{2}((\\+|-)\\d{2})".toRegex().find(time)?.groupValues
matchResult?.let {
val timeZone = matchResult[3].toInt()
val timeDifference = targetZone - timeZone
var hours = (matchResult[1].toInt() + timeDifference)
if (hours > 23) {
hours -= 24
}
return "${if (hours < 10) "0$hours" else "$hours"}:${matchResult[2]}"
} ?: error { "Wrong format of time $startTime" }
}
val date: String by lazy {
val matchResult = "^(\\d{4})(\\d{2})(\\d{2})".toRegex().find(startTime)?.groupValues
matchResult?.let { "${matchResult[3]}/${matchResult[2]}/${matchResult[1]}" }
?: error { "Wrong format of time $startTime" }
}
val formattedStartTime: String by lazy {
formatTime(startTime)
}
val formattedFinishTime: String by lazy {
formatTime(finishTime)
}
}