From 0254734bb53150aa75e8d5008b96800c2e0fdfa5 Mon Sep 17 00:00:00 2001 From: Roman Artemev Date: Mon, 27 Jan 2020 15:24:27 +0300 Subject: [PATCH] [IR] Refactored Kotlin Mangler API - Implement abstract Ir-based, Descriptor-based mangler computers and export checkers and corresponding platform specializations - Add runtime verifier which check whether all types of mangler produces the same type of data Note: code migration is not finished yet --- .../kotlin/ir/backend/js/utils/NameTables.kt | 6 +- .../jetbrains/kotlin/ir/util/KotlinMangler.kt | 39 +- .../common/serialization/KotlinMangler.kt | 362 ------------------ .../mangle/AbstractKotlinMangler.kt | 16 + .../mangle/KotlinExportChecker.kt | 12 + .../mangle/KotlinMangleComputer.kt} | 10 +- .../serialization/mangle/MangleConstant.kt | 46 +++ .../serialization/mangle/ManglerChecker.kt | 64 ++++ .../mangle/SpecialDeclarationType.kt | 13 + .../DescriptorBasedKotlinManglerImpl.kt | 66 ++++ .../DescriptorExportCheckerVisitor.kt | 95 +++++ .../descriptor/DescriptorMangleComputer.kt | 255 ++++++++++++ .../mangle/ir/IrBasedKotlinManglerImpl.kt | 18 + .../mangle/ir/IrExportCheckerVisitor.kt | 76 ++++ .../mangle/ir/IrMangleComputer.kt | 230 +++++++++++ .../serialization/mangle/mangleUtils.kt | 28 ++ .../js/lower/serialization/ir/JsMangler.kt | 72 +++- .../backend/jvm/serialization/JvmMangler.kt | 75 +++- 18 files changed, 1075 insertions(+), 408 deletions(-) delete mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinMangler.kt create mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/AbstractKotlinMangler.kt create mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/KotlinExportChecker.kt rename compiler/ir/{serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/metadata/JsKlibMetadataModuleDescriptor.kt => serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/KotlinMangleComputer.kt} (52%) create mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/MangleConstant.kt create mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/ManglerChecker.kt create mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/SpecialDeclarationType.kt create mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/descriptor/DescriptorBasedKotlinManglerImpl.kt create mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/descriptor/DescriptorExportCheckerVisitor.kt create mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/descriptor/DescriptorMangleComputer.kt create mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/ir/IrBasedKotlinManglerImpl.kt create mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/ir/IrExportCheckerVisitor.kt create mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/ir/IrMangleComputer.kt create mode 100644 compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/mangleUtils.kt diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt index e4aa06507cf..2cde28b389f 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt @@ -9,7 +9,7 @@ import org.jetbrains.kotlin.backend.common.ir.isMethodOfAny import org.jetbrains.kotlin.backend.common.ir.isTopLevel import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin -import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerForBE +import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrLoop import org.jetbrains.kotlin.ir.types.isUnit @@ -23,7 +23,7 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty fun mapToKey(declaration: T): String { - return with(JsManglerForBE) { + return with(JsManglerIr) { if (declaration is IrDeclaration && isPublic(declaration)) { declaration.hashedMangle.toString() } else if (declaration is Signature) { @@ -32,7 +32,7 @@ fun mapToKey(declaration: T): String { } } -fun JsManglerForBE.isPublic(declaration: IrDeclaration) = +fun JsManglerIr.isPublic(declaration: IrDeclaration) = declaration.isExported() && declaration !is IrScript && declaration !is IrVariable && declaration !is IrValueParameter class NameTable( diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/KotlinMangler.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/KotlinMangler.kt index b0ca62c2694..0c037eb0958 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/KotlinMangler.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/KotlinMangler.kt @@ -5,22 +5,35 @@ package org.jetbrains.kotlin.ir.util +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.ir.declarations.IrDeclaration -import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.name.Name -interface KotlinMangler { +interface KotlinMangler { + val String.hashMangle: Long - val IrDeclaration.hashedMangle: Long - fun IrDeclaration.isExported(): Boolean - val IrFunction.functionName: String - val IrType.isInlined: Boolean - val Long.isSpecial: Boolean - companion object { - private val FUNCTION_PREFIX = "" - fun functionClassSymbolName(name: Name) = "ktype:$FUNCTION_PREFIX$name" - fun functionInvokeSymbolName(name: Name) = "kfun:$FUNCTION_PREFIX$name.invoke" + fun D.isExported(): Boolean + val D.mangleString: String + + val D.hashedMangle: Long get() = mangleString.hashMangle + + val manglerName: String + + interface DescriptorMangler : KotlinMangler { + override val manglerName: String + get() = "Descriptor" + + fun ClassDescriptor.isExportEnumEntry(): Boolean + fun ClassDescriptor.mangleEnumEntryString(): String + + fun PropertyDescriptor.isExportField(): Boolean + fun PropertyDescriptor.mangleFieldString(): String + } + + interface IrMangler : KotlinMangler { + override val manglerName: String + get() = "Ir" } } diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinMangler.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinMangler.kt deleted file mode 100644 index 69c42911b78..00000000000 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinMangler.kt +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.backend.common.serialization - -import org.jetbrains.kotlin.backend.common.ir.isExpect -import org.jetbrains.kotlin.backend.common.ir.isProperExpect -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.symbols.IrClassSymbol -import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol -import org.jetbrains.kotlin.ir.types.* -import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name - -private const val PUBLIC_MANGLE_FLAG = 1L shl 63 - -abstract class KotlinManglerImpl : KotlinMangler { - - override val String.hashMangle get() = (this.cityHash64() % PUBLIC_MANGLE_FLAG) or PUBLIC_MANGLE_FLAG - - private fun hashedMangleImpl(declaration: IrDeclaration): Long { - return declaration.uniqSymbolName().hashMangle - } - - override val IrDeclaration.hashedMangle: Long - get() = hashedMangleImpl(this) - - - // We can't call "with (super) { this.isExported() }" in children. - // So provide a hook. - protected open fun IrDeclaration.isPlatformSpecificExported(): Boolean = false - - override fun IrDeclaration.isExported(): Boolean = isExportedImpl(this) - - /** - * 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. - */ - private tailrec fun isExportedImpl(declaration: IrDeclaration): Boolean { - // TODO: revise - val descriptorAnnotations = declaration.descriptor.annotations - - if (declaration.isPlatformSpecificExported()) return true - - if (declaration is IrTypeAlias && declaration.parent is IrPackageFragment) { - return true - } - - if (descriptorAnnotations.hasAnnotation(publishedApiAnnotation)) { - return true - } - - if (declaration.isAnonymousObject) - return false - - if (declaration is IrConstructor && declaration.constructedClass.kind.isSingleton) { - // Currently code generator can access the constructor of the singleton, - // so ignore visibility of the constructor itself. - return isExportedImpl(declaration.constructedClass) - } - - if (declaration is IrFunction) { - val descriptor = declaration.descriptor - // TODO: this code is required because accessor doesn't have a reference to property. - if (descriptor is PropertyAccessorDescriptor) { - val property = descriptor.correspondingProperty - if (property.annotations.hasAnnotation(publishedApiAnnotation)) return true - } - } - - val visibility = when (declaration) { - is IrClass -> declaration.visibility - is IrFunction -> declaration.visibility - is IrProperty -> declaration.visibility - is IrField -> declaration.visibility - is IrTypeAlias -> declaration.visibility - else -> null - } - - /** - * note: about INTERNAL - with support of friend modules we let frontend to deal with internal declarations. - */ - if (visibility != null && !visibility.isPublicAPI && visibility != Visibilities.INTERNAL) { - // If the declaration is explicitly marked as non-public, - // then it must not be accessible from other modules. - return false - } - - val parent = declaration.parent - if (parent is IrDeclaration) { - return isExportedImpl(parent) - } - - return true - } - - private fun IrTypeParameter.effectiveParent(): IrDeclaration = when (val irParent = parent) { - is IrClass -> irParent - is IrConstructor -> irParent - is IrSimpleFunction -> irParent.correspondingPropertySymbol?.owner ?: irParent - else -> error("Unexpected type parameter container") - } - - private fun collectTypeParameterContainers(element: IrElement): List { - val result = mutableListOf() - - tailrec fun collectTypeParameterContainersImpl(element: IrElement) { - when (element) { - is IrConstructor -> result += element - is IrSimpleFunction -> result.add(element.correspondingPropertySymbol?.owner ?: element) - is IrProperty -> result += element - is IrClass -> result += element - else -> return - } - - collectTypeParameterContainersImpl((element as IrDeclaration).parent) - } - - collectTypeParameterContainersImpl(element) - - return result - } - - private fun mapTypeParameterContainers(element: IrElement): Map { - return collectTypeParameterContainers(element).mapIndexed { i, d -> d to i }.toMap() - } - - private val publishedApiAnnotation = FqName("kotlin.PublishedApi") - - protected open fun mangleTypeParameter(typeParameter: IrTypeParameter, typeParameterNamer: (IrTypeParameter) -> String): String { - return typeParameterNamer(typeParameter) - } - - protected fun acyclicTypeMangler(type: IrType, typeParameterNamer: (IrTypeParameter) -> String): String { - - var hashString = type.classifierOrNull?.let { - when (it) { - is IrClassSymbol -> it.owner.fqNameForIrSerialization.asString() - is IrTypeParameterSymbol -> mangleTypeParameter(it.owner, typeParameterNamer) - else -> error("Unexpected type constructor") - } - } ?: "" - - when (type) { - is IrSimpleType -> { - if (!type.arguments.isEmpty()) { - hashString += "<${type.arguments.map { - when (it) { - is IrStarProjection -> "#STAR" - is IrTypeProjection -> { - val variance = it.variance.label - val projection = if (variance == "") "" else "${variance}_" - projection + acyclicTypeMangler(it.type, typeParameterNamer) - } - else -> error(it) - } - }.joinToString(",")}>" - } - - if (type.hasQuestionMark) hashString += "?" - } - !is IrDynamicType -> { - error(type) - } - } - return hashString - } - - protected fun typeToHashString(type: IrType, typeParameterNamer: (IrTypeParameter) -> String) = - acyclicTypeMangler(type, typeParameterNamer) - - fun IrValueParameter.extensionReceiverNamePart(typeParameterNamer: (IrTypeParameter) -> String): String = - "@${typeToHashString(this.type, typeParameterNamer)}." - - open fun IrFunction.valueParamsPart(typeParameterNamer: (IrTypeParameter) -> String): String { - return this.valueParameters.map { - "${typeToHashString(it.type, typeParameterNamer)}${if (it.isVararg) "_VarArg" else ""}" - }.joinToString(";") - } - - open fun IrFunction.typeParamsPart(typeParameters: List, typeParameterNamer: (IrTypeParameter) -> String): String { - if (typeParameters.isEmpty()) return "" - - fun mangleTypeParameter(index: Int, typeParameter: IrTypeParameter): String { - // We use type parameter index instead of name since changing name is not a binary-incompatible change - return typeParameter.superTypes.joinToString("&", "$index<", ">") { - acyclicTypeMangler(it, typeParameterNamer) - } - } - - return typeParameters.withIndex().joinToString(";", "{", "}") { (i, tp) -> - mangleTypeParameter(i, tp) - } - } - - open fun IrFunction.signature(typeParameterNamer: (IrTypeParameter) -> String): String { - val extensionReceiverPart = this.extensionReceiverParameter?.extensionReceiverNamePart(typeParameterNamer) ?: "" - val valueParamsPart = this.valueParamsPart(typeParameterNamer) - // Distinguish value types and references - it's needed for calling virtual methods through bridges. - // Also is function has type arguments - frontend allows exactly matching overrides. - val signatureSuffix = - when { - this.typeParameters.isNotEmpty() -> "Generic" - !returnType.isUnitOrNullableUnit() -> typeToHashString(returnType, typeParameterNamer) - else -> "" - } - - val typesParamsPart = this.typeParamsPart(typeParameters, typeParameterNamer) - - return "$extensionReceiverPart($valueParamsPart)$typesParamsPart$signatureSuffix" - } - - open val IrFunction.platformSpecificFunctionName: String? get() = null - - // TODO: rename to indicate that it has signature included - override val IrFunction.functionName: String - get() { - // TODO: Again. We can't call super in children, so provide a hook for now. - this.platformSpecificFunctionName?.let { return it } - - val typeContainerMap = mapTypeParameterContainers(this) - val typeParameterNamer: (IrTypeParameter) -> String = { - val eParent = it.effectiveParent() - "${typeContainerMap[eParent] ?: error("No parent for ${it.render()}")}:${it.index}" - } - - val name = this.name.mangleIfInternal(this.module, this.visibility) - return "$name${signature(typeParameterNamer)}" - } - - override val Long.isSpecial: Boolean - get() = specialHashes.contains(this) - - fun Name.mangleIfInternal(moduleDescriptor: ModuleDescriptor, visibility: Visibility): String = - if (visibility != Visibilities.INTERNAL) { - this.asString() - } else { - val moduleName = moduleDescriptor.name.asString() - .let { it.substring(1, it.lastIndex) } // Remove < and >. - - "$this\$$moduleName" - } - - val IrField.symbolName: String - get() { - val containingDeclarationPart = parent.fqNameForIrSerialization.let { - if (it.isRoot) "" else "$it." - } - return "kfield:$containingDeclarationPart$name" - - } - - val IrClass.typeInfoSymbolName: String - get() { - assert(isExportedImpl(this)) - if (isBuiltInFunction(this)) - return KotlinMangler.functionClassSymbolName(name) - return "ktype:" + this.fqNameForIrSerialization.toString() - } - - val IrTypeParameter.symbolName: String - get() { - - val parentDeclaration = (parent as? IrSimpleFunction)?.correspondingPropertySymbol?.owner ?: parent - val containingDeclarationPart = when (parentDeclaration) { - is IrDeclaration -> parentDeclaration.uniqSymbolName() - else -> error("Unexpected type parameter parent") - } - return "ktypeparam:$containingDeclarationPart$name@$index" - } - - val IrTypeAlias.symbolName: String - get() { - val containingDeclarationPart = parent.fqNameForIrSerialization.let { - if (it.isRoot) "" else "$it." - } - return "ktypealias:$containingDeclarationPart$name" - } - -// This is a little extension over what's used in real mangling -// since some declarations never appear in the bitcode symbols. - - internal fun IrDeclaration.uniqSymbolName(): String = when (this) { - is IrFunction -> this.uniqFunctionName - is IrProperty -> this.symbolName - is IrClass -> this.typeInfoSymbolName - is IrField -> this.symbolName - is IrEnumEntry -> this.symbolName - is IrTypeParameter -> this.symbolName - is IrTypeAlias -> this.symbolName - else -> error("Unexpected exported declaration: $this") - } + expectPart - - // TODO: need to figure out the proper OptionalExpectation behavior - private val IrDeclaration.expectPart get() = if (this.isProperExpect) "#expect" else "" - - private val IrDeclarationParent.fqNameUnique: FqName - get() = when (this) { - is IrPackageFragment -> this.fqName - is IrDeclaration -> this.parent.fqNameUnique.child(this.uniqName) - else -> error(this) - } - - private val IrDeclaration.uniqName: Name - get() = when (this) { - is IrSimpleFunction -> Name.special("<${this.uniqFunctionName}>") - else -> this.nameForIrSerialization - } - - private val IrProperty.symbolName: String - get() { - val typeContainerMap = mapTypeParameterContainers(this) - val typeParameterNamer: (IrTypeParameter) -> String = { - val eParent = it.effectiveParent() - "${typeContainerMap[eParent] ?: error("No parent for ${it.render()}")}:${it.index}" - } - - val extensionReceiver: String = getter?.extensionReceiverParameter?.extensionReceiverNamePart(typeParameterNamer) ?: "" - - val containingDeclarationPart = parent.fqNameForIrSerialization.let { - if (it.isRoot) "" else "$it." - } - return "kprop:$containingDeclarationPart$extensionReceiver$name" - } - - private val IrEnumEntry.symbolName: String - get() { - val containingDeclarationPart = parent.fqNameForIrSerialization.let { - if (it.isRoot) "" else "$it." - } - return "kenumentry:$containingDeclarationPart$name" - } - - // This is basicly the same as .symbolName, but disambiguates external functions with the same C name. -// In addition functions appearing in fq sequence appear as . - private val IrFunction.uniqFunctionName: String - get() { - if (isBuiltInFunction(this)) - return KotlinMangler.functionInvokeSymbolName(parentAsClass.name) - val parent = this.parent - - val containingDeclarationPart = parent.fqNameUnique.let { - if (it.isRoot) "" else "$it." - } - - return "kfun:$containingDeclarationPart#$functionName" - } - - private val specialHashes = listOf("Function", "KFunction", "SuspendFunction", "KSuspendFunction") - .flatMap { name -> - (0..255).map { KotlinMangler.functionClassSymbolName(Name.identifier(name + it)) } - }.map { it.hashMangle } - .toSet() -} diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/AbstractKotlinMangler.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/AbstractKotlinMangler.kt new file mode 100644 index 00000000000..88e0a252c32 --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/AbstractKotlinMangler.kt @@ -0,0 +1,16 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.common.serialization.mangle + +import org.jetbrains.kotlin.backend.common.serialization.cityHash64 +import org.jetbrains.kotlin.ir.util.KotlinMangler + +abstract class AbstractKotlinMangler : KotlinMangler { + override val String.hashMangle get() = cityHash64() + + protected abstract fun getExportChecker(): KotlinExportChecker + protected abstract fun getMangleComputer(prefix: String): KotlinMangleComputer +} \ No newline at end of file diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/KotlinExportChecker.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/KotlinExportChecker.kt new file mode 100644 index 00000000000..2b44cc787eb --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/KotlinExportChecker.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.common.serialization.mangle + +interface KotlinExportChecker { + fun check(declaration: D, type: SpecialDeclarationType): Boolean + + fun D.isPlatformSpecificExported(): Boolean +} \ No newline at end of file diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/metadata/JsKlibMetadataModuleDescriptor.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/KotlinMangleComputer.kt similarity index 52% rename from compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/metadata/JsKlibMetadataModuleDescriptor.kt rename to compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/KotlinMangleComputer.kt index 195f1428d91..2f2464c7598 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/metadata/JsKlibMetadataModuleDescriptor.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/KotlinMangleComputer.kt @@ -3,10 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata +package org.jetbrains.kotlin.backend.common.serialization.mangle -class JsKlibMetadataModuleDescriptor( - val name: String, - val imported: List, - val data: T -) +interface KotlinMangleComputer { + fun computeMangle(declaration: D): String +} \ No newline at end of file diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/MangleConstant.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/MangleConstant.kt new file mode 100644 index 00000000000..71e01d0ed04 --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/MangleConstant.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.common.serialization.mangle + +enum class MangleConstant(val prefix: Char, val separator: Char, val suffix: Char) { + VALUE_PARAMETERS('(', ';', ')'), + TYPE_PARAMETERS('{', ';', '}'), + UPPER_BOUNDS('<', '&', '>'), + TYPE_ARGUMENTS('<', ',', '>'), + FLEXIBLE_TYPE('[', '~', ']'); + + companion object { + const val VAR_ARG_MARK = "..." + const val STAR_MARK = '*' + const val Q_MARK = '?' + const val EXPECT_MARK = "#expect" + const val UNKNOWN_MARK = "" + const val DYNAMIC_MARK = "" + + const val VARIANCE_SEPARATOR = '|' + const val UPPER_BOUND_SEPARATOR = 'ยง' + const val PREFIX_SEPARATOR = ':' + const val MODULE_SEPARATOR = '$' + const val FQN_SEPARATOR = '.' + const val INDEX_SEPARATOR = ':' + + const val PLATFORM_FUNCTION_MARKER = '%' + + const val EXTENSION_RECEIVER_PREFIX = '@' + const val FUNCTION_NAME_PREFIX = '#' + const val TYPE_PARAM_INDEX_PREFIX = '@' + + const val EMPTY_PREFIX = "" + + const val FUN_PREFIX = "kfun" + const val CLASS_PREFIX = "kclass" + const val PROPERTY_PREFIX = "kprop" + const val FIELD_PREFIX = "kfield" + const val ENUM_ENTRY_PREFIX = "kenumentry" + const val TYPE_ALIAS_PREFIX = "ktypealias" + const val TYPE_PARAM_PREFIX = "ktypeparam" + } +} \ No newline at end of file diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/ManglerChecker.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/ManglerChecker.kt new file mode 100644 index 00000000000..a4098834bad --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/ManglerChecker.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.common.serialization.mangle + +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.util.KotlinMangler +import org.jetbrains.kotlin.ir.util.render +import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid +import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid + +class ManglerChecker(vararg _manglers: KotlinMangler) : IrElementVisitorVoid { + + private val manglers = _manglers.toList() + + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + + private fun KotlinMangler.isExportCheck(declaration: IrDeclaration) = declaration.isExported() + private fun KotlinMangler.stringMangle(declaration: IrDeclaration) = declaration.mangleString + + private fun Iterable.checkAllEqual(init: R, op: T.() -> R, onError: (T, R, T, R) -> Unit): R { + var prev: T? = null + + var r = init + + for (it in this) { + if (prev == null) { + r = it.op() + prev = it + } else { + val tmp = it.op() + if (r != tmp) { + onError(prev, r, it, tmp) + } + prev = it + r = tmp + } + } + + return r + } + + override fun visitDeclaration(declaration: IrDeclaration) { + + val exported = manglers.checkAllEqual(false, { isExportCheck(declaration) }) { m1, r1, m2, r2 -> + println("${declaration.render()}\n ${m1.manglerName}: $r1\n ${m2.manglerName}: $r2\n") + error("${declaration.render()}\n ${m1.manglerName}: $r1\n ${m2.manglerName}: $r2\n") + } + + if (!exported) return + + manglers.checkAllEqual("", { stringMangle(declaration) }) { m1, r1, m2, r2 -> + println("${declaration.render()}\n ${m1.manglerName}: $r1\n ${m2.manglerName}: $r2\n") + error("${declaration.render()}\n ${m1.manglerName}: $r1\n ${m2.manglerName}: $r2\n") + } + + declaration.acceptChildrenVoid(this) + } +} \ No newline at end of file diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/SpecialDeclarationType.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/SpecialDeclarationType.kt new file mode 100644 index 00000000000..f1976c98740 --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/SpecialDeclarationType.kt @@ -0,0 +1,13 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.common.serialization.mangle + +enum class SpecialDeclarationType { + REGULAR, + ANON_INIT, + BACKING_FIELD, + ENUM_ENTRY; +} \ No newline at end of file diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/descriptor/DescriptorBasedKotlinManglerImpl.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/descriptor/DescriptorBasedKotlinManglerImpl.kt new file mode 100644 index 00000000000..015aa2ea6b5 --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/descriptor/DescriptorBasedKotlinManglerImpl.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.common.serialization.mangle.descriptor + +import org.jetbrains.kotlin.backend.common.serialization.mangle.AbstractKotlinMangler +import org.jetbrains.kotlin.backend.common.serialization.mangle.KotlinMangleComputer +import org.jetbrains.kotlin.backend.common.serialization.mangle.MangleConstant +import org.jetbrains.kotlin.backend.common.serialization.mangle.SpecialDeclarationType +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.ir.declarations.IrAnonymousInitializer +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.declarations.IrEnumEntry +import org.jetbrains.kotlin.ir.declarations.IrField +import org.jetbrains.kotlin.ir.util.KotlinMangler + +abstract class DescriptorBasedKotlinManglerImpl : AbstractKotlinMangler(), KotlinMangler.DescriptorMangler { + private fun withPrefix(prefix: String, descriptor: DeclarationDescriptor): String = + getMangleComputer(prefix).computeMangle(descriptor) + + override fun ClassDescriptor.mangleEnumEntryString(): String = withPrefix(MangleConstant.ENUM_ENTRY_PREFIX, this) + + override fun ClassDescriptor.isExportEnumEntry(): Boolean = + getExportChecker().check(this, SpecialDeclarationType.ENUM_ENTRY) + + override fun PropertyDescriptor.isExportField(): Boolean = false + + override fun PropertyDescriptor.mangleFieldString(): String = error("Fields supposed to be non-exporting") + + override val DeclarationDescriptor.mangleString: String + get() = withPrefix(MangleConstant.EMPTY_PREFIX, this) + + override fun DeclarationDescriptor.isExported(): Boolean = getExportChecker().check(this, SpecialDeclarationType.REGULAR) +} + +class Ir2DescriptorManglerAdapter(private val delegate: DescriptorBasedKotlinManglerImpl) : AbstractKotlinMangler(), + KotlinMangler.IrMangler { + override val manglerName: String + get() = delegate.manglerName + + override fun IrDeclaration.isExported(): Boolean { + return when (this) { + is IrAnonymousInitializer -> false + is IrEnumEntry -> delegate.run { descriptor.isExportEnumEntry() } + is IrField -> delegate.run { descriptor.isExportField() } + else -> delegate.run { descriptor.isExported() } + } + } + + override val IrDeclaration.mangleString: String + get() { + return when (this) { + is IrEnumEntry -> delegate.run { descriptor.mangleEnumEntryString() } + is IrField -> delegate.run { descriptor.mangleFieldString() } + else -> delegate.run { descriptor.mangleString } + } + } + + override fun getExportChecker() = error("Should not have been reached") + + override fun getMangleComputer(prefix: String): KotlinMangleComputer = error("Should not have been reached") +} \ No newline at end of file diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/descriptor/DescriptorExportCheckerVisitor.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/descriptor/DescriptorExportCheckerVisitor.kt new file mode 100644 index 00000000000..bea5000ee57 --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/descriptor/DescriptorExportCheckerVisitor.kt @@ -0,0 +1,95 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.common.serialization.mangle.descriptor + +import org.jetbrains.kotlin.backend.common.serialization.mangle.KotlinExportChecker +import org.jetbrains.kotlin.backend.common.serialization.mangle.SpecialDeclarationType +import org.jetbrains.kotlin.backend.common.serialization.mangle.publishedApiAnnotation +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.name.SpecialNames + +abstract class DescriptorExportCheckerVisitor : DeclarationDescriptorVisitor, + KotlinExportChecker { + + override fun check(declaration: DeclarationDescriptor, type: SpecialDeclarationType): Boolean { + return declaration.accept(this, type) + } + + private fun reportUnexpectedDescriptor(descriptor: DeclarationDescriptor): Nothing { + error("unexpected descriptor $descriptor") + } + + private fun Visibility.isPubliclyVisible(): Boolean = isPublicAPI || this === Visibilities.INTERNAL + + private fun DeclarationDescriptorNonRoot.isExported(annotations: Annotations, visibility: Visibility?): Boolean { + if (annotations.hasAnnotation(publishedApiAnnotation)) return true + if (visibility != null && !visibility.isPubliclyVisible()) return false + + return containingDeclaration.accept(this@DescriptorExportCheckerVisitor, SpecialDeclarationType.REGULAR) ?: false + } + + override fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor, data: SpecialDeclarationType) = true + + override fun visitPackageViewDescriptor(descriptor: PackageViewDescriptor, data: SpecialDeclarationType) = true + + override fun visitVariableDescriptor(descriptor: VariableDescriptor, data: SpecialDeclarationType) = false + + override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: SpecialDeclarationType): Boolean { + return descriptor.run { isExported(annotations, visibility) } + } + + override fun visitTypeParameterDescriptor(descriptor: TypeParameterDescriptor, data: SpecialDeclarationType): Boolean = false + + override fun visitClassDescriptor(descriptor: ClassDescriptor, data: SpecialDeclarationType): Boolean { + if (data == SpecialDeclarationType.ANON_INIT) return false + if (descriptor.name == SpecialNames.NO_NAME_PROVIDED) return false + if (descriptor.kind == ClassKind.ENUM_ENTRY && data == SpecialDeclarationType.REGULAR) return false + return descriptor.run { isExported(annotations, visibility) } + } + + override fun visitTypeAliasDescriptor(descriptor: TypeAliasDescriptor, data: SpecialDeclarationType) = + if (descriptor.containingDeclaration is PackageFragmentDescriptor) true + else descriptor.run { isExported(annotations, visibility) } + + override fun visitModuleDeclaration(descriptor: ModuleDescriptor, data: SpecialDeclarationType): Boolean { + reportUnexpectedDescriptor(descriptor) + } + + override fun visitConstructorDescriptor(constructorDescriptor: ConstructorDescriptor, data: SpecialDeclarationType): Boolean { + val klass = constructorDescriptor.constructedClass + return if (klass.kind.isSingleton) + klass.accept(this, SpecialDeclarationType.REGULAR) + else constructorDescriptor.run { isExported(annotations, visibility) } + } + + override fun visitScriptDescriptor(scriptDescriptor: ScriptDescriptor, data: SpecialDeclarationType): Boolean { + reportUnexpectedDescriptor(scriptDescriptor) + } + + override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, data: SpecialDeclarationType): Boolean { + val visibility = if (data == SpecialDeclarationType.BACKING_FIELD) { + return false + } else descriptor.visibility + + return descriptor.run { isExported(annotations, visibility) } + } + + override fun visitValueParameterDescriptor(descriptor: ValueParameterDescriptor, data: SpecialDeclarationType): Boolean { + return false + } + + override fun visitPropertyGetterDescriptor(descriptor: PropertyGetterDescriptor, data: SpecialDeclarationType): Boolean { + return descriptor.run { isExported(correspondingProperty.annotations, visibility) } + } + + override fun visitPropertySetterDescriptor(descriptor: PropertySetterDescriptor, data: SpecialDeclarationType): Boolean { + return descriptor.run { isExported(correspondingProperty.annotations, visibility) } + } + + override fun visitReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor, data: SpecialDeclarationType) = false + +} \ No newline at end of file diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/descriptor/DescriptorMangleComputer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/descriptor/DescriptorMangleComputer.kt new file mode 100644 index 00000000000..1f4a55b5b9b --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/descriptor/DescriptorMangleComputer.kt @@ -0,0 +1,255 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.common.serialization.mangle.descriptor + +import org.jetbrains.kotlin.backend.common.serialization.mangle.KotlinMangleComputer +import org.jetbrains.kotlin.backend.common.serialization.mangle.MangleConstant +import org.jetbrains.kotlin.backend.common.serialization.mangle.collect +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.resolve.descriptorUtil.module +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.typeUtil.isUnit +import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty + +abstract class DescriptorMangleComputer(protected val builder: StringBuilder, protected val specialPrefix: String) : + DeclarationDescriptorVisitor, KotlinMangleComputer { + + override fun computeMangle(declaration: DeclarationDescriptor): String { + declaration.accept(this, true) + return builder.toString() + } + + protected abstract fun copy(): DescriptorMangleComputer + + private val typeParameterContainer = ArrayList(4) + + private var isRealExpect = false + + private fun addPrefix(prefix: String, addPrefix: Boolean): Int { + if (addPrefix) { + builder.append(prefix) + builder.append(MangleConstant.PREFIX_SEPARATOR) + } + return builder.length + } + + private fun DeclarationDescriptor.mangleSimpleDeclaration(prefix: String, addPrefix: Boolean, name: String) { + val prefixLength = addPrefix(prefix, addPrefix) + containingDeclaration?.accept(this@DescriptorMangleComputer, false) + + if (prefixLength != builder.length) builder.append(MangleConstant.FQN_SEPARATOR) + + builder.append(name) + } + + open val FunctionDescriptor.platformSpecificFunctionName: String? get() = null + + private fun reportUnexpectedDescriptor(descriptor: DeclarationDescriptor) { + error("unexpected descriptor $descriptor") + } + + open fun FunctionDescriptor.platformSpecificSuffix(): String? = null + + private fun FunctionDescriptor.mangleFunction(isCtor: Boolean, prefix: Boolean, container: CallableDescriptor) { + + isRealExpect = isRealExpect or isExpect + + val prefixLength = addPrefix(MangleConstant.FUN_PREFIX, prefix) + + typeParameterContainer.add(container) + container.containingDeclaration.accept(this@DescriptorMangleComputer, false) + + if (prefixLength != builder.length) builder.append(MangleConstant.FQN_SEPARATOR) + + builder.append(MangleConstant.FUNCTION_NAME_PREFIX) + + if (visibility != Visibilities.INTERNAL) builder.append(name) + else { + builder.append(name) + builder.append(MangleConstant.MODULE_SEPARATOR) + builder.append(module.name.asString().run { substring(1, lastIndex) }) + } + + mangleSignature(isCtor, container) + + platformSpecificSuffix()?.let { + builder.append(MangleConstant.PLATFORM_FUNCTION_MARKER) + builder.append(it) + } + + if (prefix && isRealExpect) builder.append(MangleConstant.EXPECT_MARK) + } + + private fun FunctionDescriptor.mangleSignature(isCtor: Boolean, realTypeParameterContainer: CallableDescriptor) { + + extensionReceiverParameter?.let { + builder.append(MangleConstant.EXTENSION_RECEIVER_PREFIX) + mangleExtensionReceiverParameter(builder, it) + } + + valueParameters.collect(builder, MangleConstant.VALUE_PARAMETERS) { mangleValueParameter(this, it) } + realTypeParameterContainer.typeParameters.filter { it.containingDeclaration == realTypeParameterContainer } + .collect(builder, MangleConstant.TYPE_PARAMETERS) { mangleTypeParameter(this, it) } + + returnType?.run { + if (!isCtor && !isUnit()) { + mangleType(builder, this) + } + } + } + + private fun mangleExtensionReceiverParameter(vpBuilder: StringBuilder, param: ReceiverParameterDescriptor) { + mangleType(vpBuilder, param.type) + } + + private fun mangleValueParameter(vpBuilder: StringBuilder, param: ValueParameterDescriptor) { + mangleType(vpBuilder, param.type) + + if (param.varargElementType != null) vpBuilder.append(MangleConstant.VAR_ARG_MARK) + } + + private fun mangleTypeParameter(tpBuilder: StringBuilder, param: TypeParameterDescriptor) { + tpBuilder.append(param.index) + tpBuilder.append(MangleConstant.UPPER_BOUND_SEPARATOR) + + param.upperBounds.collect(tpBuilder, MangleConstant.UPPER_BOUNDS) { mangleType(this, it) } + } + + private fun mangleType(tBuilder: StringBuilder, wtype: KotlinType) { + when (val type = wtype.unwrap()) { + is SimpleType -> { + when (val classifier = type.constructor.declarationDescriptor) { + is ClassDescriptor -> classifier.accept(copy(), false) + is TypeParameterDescriptor -> tBuilder.mangleTypeParameterReference(classifier) + else -> error("Unexpected classifier: $classifier") + } + + type.arguments.ifNotEmpty { + collect(tBuilder, MangleConstant.TYPE_ARGUMENTS) { arg -> + if (arg.isStarProjection) { + append(MangleConstant.STAR_MARK) + } else { + if (arg.projectionKind != Variance.INVARIANT) { + append(arg.projectionKind.label) + append(MangleConstant.VARIANCE_SEPARATOR) + } + + mangleType(this, arg.type) + } + } + } + + if (type.isMarkedNullable) tBuilder.append(MangleConstant.Q_MARK) + } + is DynamicType -> tBuilder.append(MangleConstant.DYNAMIC_MARK) + is FlexibleType -> { + // TODO: is that correct way to mangle flexible type? + with(MangleConstant.FLEXIBLE_TYPE) { + tBuilder.append(prefix) + mangleType(tBuilder, type.lowerBound) + tBuilder.append(separator) + mangleType(tBuilder, type.upperBound) + tBuilder.append(suffix) + } + } + else -> error("Unexpected type $wtype") + } + } + + private fun StringBuilder.mangleTypeParameterReference(typeParameter: TypeParameterDescriptor) { + val parent = typeParameter.containingDeclaration + val ci = typeParameterContainer.indexOf(parent) + // TODO: what should we do in this case? +// require(ci >= 0) { "No type container found for ${typeParameter.render()}" } + append(ci) + append(MangleConstant.INDEX_SEPARATOR) + append(typeParameter.index) + } + + override fun visitPackageFragmentDescriptor(descriptor: PackageFragmentDescriptor, data: Boolean) { + descriptor.fqName.let { if (!it.isRoot) builder.append(it.asString()) } + } + + override fun visitPackageViewDescriptor(descriptor: PackageViewDescriptor, data: Boolean) = reportUnexpectedDescriptor(descriptor) + + override fun visitVariableDescriptor(descriptor: VariableDescriptor, data: Boolean) = reportUnexpectedDescriptor(descriptor) + + override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Boolean) { + descriptor.platformSpecificFunctionName?.let { + builder.append(it) + return + } + + descriptor.mangleFunction(false, data, descriptor) + } + + override fun visitTypeParameterDescriptor(descriptor: TypeParameterDescriptor, data: Boolean) { + addPrefix(MangleConstant.TYPE_PARAM_PREFIX, data) + descriptor.containingDeclaration.accept(this, data) + + builder.append(MangleConstant.TYPE_PARAM_INDEX_PREFIX) + builder.append(descriptor.index) + } + + override fun visitClassDescriptor(descriptor: ClassDescriptor, data: Boolean) { + isRealExpect = isRealExpect or descriptor.isExpect + typeParameterContainer.add(descriptor) + val prefix = if (specialPrefix == MangleConstant.ENUM_ENTRY_PREFIX) specialPrefix else MangleConstant.CLASS_PREFIX + descriptor.mangleSimpleDeclaration(prefix, data, descriptor.name.asString()) + + if (data && isRealExpect) builder.append(MangleConstant.EXPECT_MARK) + } + + override fun visitTypeAliasDescriptor(descriptor: TypeAliasDescriptor, data: Boolean) { + descriptor.mangleSimpleDeclaration(MangleConstant.TYPE_ALIAS_PREFIX, data, descriptor.name.asString()) + } + + override fun visitModuleDeclaration(descriptor: ModuleDescriptor, data: Boolean) = reportUnexpectedDescriptor(descriptor) + + override fun visitConstructorDescriptor(constructorDescriptor: ConstructorDescriptor, data: Boolean) { + constructorDescriptor.mangleFunction(true, data, constructorDescriptor) + } + + override fun visitScriptDescriptor(scriptDescriptor: ScriptDescriptor, data: Boolean) = reportUnexpectedDescriptor(scriptDescriptor) + + override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, data: Boolean) { + val extensionReceiver = descriptor.extensionReceiverParameter + + val prefix = if (specialPrefix == MangleConstant.FIELD_PREFIX) specialPrefix else MangleConstant.PROPERTY_PREFIX + val prefixLength = addPrefix(prefix, data) + + isRealExpect = isRealExpect or descriptor.isExpect + typeParameterContainer.add(descriptor) + descriptor.containingDeclaration.accept(this, false) + + if (prefixLength != builder.length) builder.append(MangleConstant.FQN_SEPARATOR) + + if (extensionReceiver != null) { + builder.append(MangleConstant.EXTENSION_RECEIVER_PREFIX) + mangleExtensionReceiverParameter(builder, extensionReceiver) + } + + builder.append(descriptor.name) + if (data && isRealExpect) builder.append(MangleConstant.EXPECT_MARK) + } + + override fun visitValueParameterDescriptor(descriptor: ValueParameterDescriptor, data: Boolean) = reportUnexpectedDescriptor(descriptor) + + private fun manglePropertyAccessor(accessor: PropertyAccessorDescriptor, data: Boolean) { + accessor.mangleFunction(false, data, accessor.correspondingProperty) + } + + override fun visitPropertyGetterDescriptor(descriptor: PropertyGetterDescriptor, data: Boolean) { + manglePropertyAccessor(descriptor, data) + } + + override fun visitPropertySetterDescriptor(descriptor: PropertySetterDescriptor, data: Boolean) { + manglePropertyAccessor(descriptor, data) + } + + override fun visitReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor, data: Boolean) = + reportUnexpectedDescriptor(descriptor) +} \ No newline at end of file diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/ir/IrBasedKotlinManglerImpl.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/ir/IrBasedKotlinManglerImpl.kt new file mode 100644 index 00000000000..3b95c25eb33 --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/ir/IrBasedKotlinManglerImpl.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.common.serialization.mangle.ir + +import org.jetbrains.kotlin.backend.common.serialization.mangle.AbstractKotlinMangler +import org.jetbrains.kotlin.backend.common.serialization.mangle.SpecialDeclarationType +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.util.KotlinMangler + +abstract class IrBasedKotlinManglerImpl : AbstractKotlinMangler(), KotlinMangler.IrMangler { + override val IrDeclaration.mangleString: String + get() = getMangleComputer("").computeMangle(this) + + override fun IrDeclaration.isExported(): Boolean = getExportChecker().check(this, SpecialDeclarationType.REGULAR) +} \ No newline at end of file diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/ir/IrExportCheckerVisitor.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/ir/IrExportCheckerVisitor.kt new file mode 100644 index 00000000000..a73a01a68ce --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/ir/IrExportCheckerVisitor.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.common.serialization.mangle.ir + +import org.jetbrains.kotlin.backend.common.serialization.mangle.KotlinExportChecker +import org.jetbrains.kotlin.backend.common.serialization.mangle.SpecialDeclarationType +import org.jetbrains.kotlin.backend.common.serialization.mangle.publishedApiAnnotation +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.descriptors.Visibility +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.IrConstructorCall +import org.jetbrains.kotlin.ir.util.constructedClass +import org.jetbrains.kotlin.ir.util.hasAnnotation +import org.jetbrains.kotlin.ir.util.render +import org.jetbrains.kotlin.ir.visitors.IrElementVisitor +import org.jetbrains.kotlin.name.SpecialNames + +abstract class IrExportCheckerVisitor : IrElementVisitor, KotlinExportChecker { + + override fun check(declaration: IrDeclaration, type: SpecialDeclarationType): Boolean { + return declaration.accept(this, null) + } + + abstract override fun IrDeclaration.isPlatformSpecificExported(): Boolean + + private fun IrDeclaration.isExported(annotations: List, visibility: Visibility?): Boolean { + if (annotations.hasAnnotation(publishedApiAnnotation)) return true + if (visibility != null && !visibility.isPubliclyVisible()) return false + + return parent.accept(this@IrExportCheckerVisitor, null) + } + + private fun Visibility.isPubliclyVisible(): Boolean = isPublicAPI || this === Visibilities.INTERNAL + + override fun visitElement(element: IrElement, data: Nothing?): Boolean = error("Should bot reach here ${element.render()}") + + override fun visitDeclaration(declaration: IrDeclaration, data: Nothing?) = declaration.run { isExported(annotations, null) } + + override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer, data: Nothing?) = false + override fun visitValueParameter(declaration: IrValueParameter, data: Nothing?) = false + override fun visitVariable(declaration: IrVariable, data: Nothing?) = false + override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty, data: Nothing?) = false + + override fun visitTypeParameter(declaration: IrTypeParameter, data: Nothing?) = false + + override fun visitField(declaration: IrField, data: Nothing?) = false + + override fun visitProperty(declaration: IrProperty, data: Nothing?): Boolean { + return declaration.run { isExported(annotations, visibility) } + } + + override fun visitPackageFragment(declaration: IrPackageFragment, data: Nothing?): Boolean = true + + override fun visitTypeAlias(declaration: IrTypeAlias, data: Nothing?): Boolean = + if (declaration.parent is IrPackageFragment) true + else declaration.run { isExported(annotations, visibility) } + + override fun visitClass(declaration: IrClass, data: Nothing?): Boolean { + if (declaration.name == SpecialNames.NO_NAME_PROVIDED) return false + return declaration.run { isExported(annotations, visibility) } + } + + override fun visitConstructor(declaration: IrConstructor, data: Nothing?): Boolean { + val klass = declaration.constructedClass + return if (klass.kind.isSingleton) klass.accept(this, null) else declaration.run { isExported(annotations, visibility) } + } + + override fun visitSimpleFunction(declaration: IrSimpleFunction, data: Nothing?): Boolean { + val annotations = declaration.run { correspondingPropertySymbol?.owner?.annotations ?: annotations } + return declaration.run { isExported(annotations, visibility) } + } +} diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/ir/IrMangleComputer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/ir/IrMangleComputer.kt new file mode 100644 index 00000000000..be73e0b9654 --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/ir/IrMangleComputer.kt @@ -0,0 +1,230 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.common.serialization.mangle.ir + +import org.jetbrains.kotlin.backend.common.serialization.mangle.KotlinMangleComputer +import org.jetbrains.kotlin.backend.common.serialization.mangle.MangleConstant +import org.jetbrains.kotlin.backend.common.serialization.mangle.collect +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol +import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.util.isVararg +import org.jetbrains.kotlin.ir.util.module +import org.jetbrains.kotlin.ir.util.render +import org.jetbrains.kotlin.ir.visitors.IrElementVisitor +import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty + +abstract class IrMangleComputer(protected val builder: StringBuilder) : IrElementVisitor, + KotlinMangleComputer { + + private val typeParameterContainer = ArrayList(4) + + private var isRealExpect = false + + open val IrFunction.platformSpecificFunctionName: String? get() = null + + protected abstract fun copy(): IrMangleComputer + + override fun computeMangle(declaration: IrDeclaration): String { + declaration.accept(this, true) + return builder.toString() + } + + private fun addPrefix(prefix: String, addPrefix: Boolean): Int { + if (addPrefix) { + builder.append(prefix) + builder.append(MangleConstant.PREFIX_SEPARATOR) + } + return builder.length + } + + private fun IrDeclaration.mangleSimpleDeclaration(prefix: String, addPrefix: Boolean, name: String) { + val prefixLength = addPrefix(prefix, addPrefix) + parent.accept(this@IrMangleComputer, false) + + if (prefixLength != builder.length) builder.append(MangleConstant.FQN_SEPARATOR) + + builder.append(name) + } + + private fun IrFunction.mangleFunction(isCtor: Boolean, prefix: Boolean, container: IrDeclaration) { + + isRealExpect = isRealExpect or isExpect + + val prefixLength = addPrefix(MangleConstant.FUN_PREFIX, prefix) + + typeParameterContainer.add(container) + container.parent.accept(this@IrMangleComputer, false) + + if (prefixLength != builder.length) builder.append(MangleConstant.FQN_SEPARATOR) + + builder.append(MangleConstant.FUNCTION_NAME_PREFIX) + + if (visibility != Visibilities.INTERNAL) builder.append(name) + else { + builder.append(name) + builder.append(MangleConstant.MODULE_SEPARATOR) + val moduleName = try { + module.name.asString().run { substring(1, lastIndex) } + } catch (e: Throwable) { + MangleConstant.UNKNOWN_MARK + } + builder.append(moduleName) + } + + mangleSignature(isCtor) + + if (prefix && isRealExpect) builder.append(MangleConstant.EXPECT_MARK) + } + + private fun IrFunction.mangleSignature(isCtor: Boolean) { + + extensionReceiverParameter?.let { + builder.append(MangleConstant.EXTENSION_RECEIVER_PREFIX) + mangleValueParameter(builder, it) + } + + valueParameters.collect(builder, MangleConstant.VALUE_PARAMETERS) { mangleValueParameter(this, it) } + typeParameters.collect(builder, MangleConstant.TYPE_PARAMETERS) { mangleTypeParameter(this, it) } + + if (!isCtor && !returnType.isUnit()) { + mangleType(builder, returnType) + } + } + + private fun IrTypeParameter.effectiveParent(): IrDeclaration = when (val irParent = parent) { + is IrSimpleFunction -> irParent.correspondingPropertySymbol?.owner ?: irParent + is IrTypeParametersContainer -> irParent + else -> error("Unexpected type parameter container ${irParent.render()} for TP ${render()}") + } + + private fun mangleValueParameter(vpBuilder: StringBuilder, param: IrValueParameter) { + mangleType(vpBuilder, param.type) + + if (param.isVararg) vpBuilder.append(MangleConstant.VAR_ARG_MARK) + } + + private fun mangleTypeParameter(tpBuilder: StringBuilder, param: IrTypeParameter) { + tpBuilder.append(param.index) + tpBuilder.append(MangleConstant.UPPER_BOUND_SEPARATOR) + + param.superTypes.collect(tpBuilder, MangleConstant.UPPER_BOUNDS) { mangleType(this, it) } + } + + private fun StringBuilder.mangleTypeParameterReference(typeParameter: IrTypeParameter) { + val parent = typeParameter.effectiveParent() + val ci = typeParameterContainer.indexOf(parent) + // TODO: what should we do in this case? +// require(ci >= 0) { "No type container found for ${typeParameter.render()}" } + append(ci) + append(MangleConstant.INDEX_SEPARATOR) + append(typeParameter.index) + } + + private fun mangleType(tBuilder: StringBuilder, type: IrType) { + when (type) { + is IrSimpleType -> { + when (val classifier = type.classifier) { + is IrClassSymbol -> classifier.owner.accept(copy(), false) + is IrTypeParameterSymbol -> tBuilder.mangleTypeParameterReference(classifier.owner) + } + + type.arguments.ifNotEmpty { + collect(tBuilder, MangleConstant.TYPE_ARGUMENTS) { arg -> + when (arg) { + is IrStarProjection -> append(MangleConstant.STAR_MARK) + is IrTypeProjection -> { + if (arg.variance != Variance.INVARIANT) { + append(arg.variance.label) + append(MangleConstant.VARIANCE_SEPARATOR) + } + + mangleType(this, arg.type) + } + } + } + } + + if (type.hasQuestionMark) tBuilder.append(MangleConstant.Q_MARK) + } + is IrDynamicType -> tBuilder.append(MangleConstant.DYNAMIC_MARK) + else -> error("Unexpected type $type") + } + } + + override fun visitElement(element: IrElement, data: Boolean) = error("unexpected element ${element.render()}") + + override fun visitClass(declaration: IrClass, data: Boolean) { + isRealExpect = isRealExpect or declaration.isExpect + typeParameterContainer.add(declaration) + declaration.mangleSimpleDeclaration(MangleConstant.CLASS_PREFIX, data, declaration.name.asString()) + + if (data && isRealExpect) builder.append(MangleConstant.EXPECT_MARK) + } + + override fun visitPackageFragment(declaration: IrPackageFragment, data: Boolean) { + declaration.fqName.let { if (!it.isRoot) builder.append(it.asString()) } + } + + override fun visitProperty(declaration: IrProperty, data: Boolean) { + val extensionReceiver = declaration.run { (getter ?: setter)?.extensionReceiverParameter } + + val prefixLength = addPrefix(MangleConstant.PROPERTY_PREFIX, data) + + isRealExpect = isRealExpect or declaration.isExpect + typeParameterContainer.add(declaration) + declaration.parent.accept(this, false) + + if (prefixLength != builder.length) builder.append(MangleConstant.FQN_SEPARATOR) + + if (extensionReceiver != null) { + builder.append(MangleConstant.EXTENSION_RECEIVER_PREFIX) + mangleValueParameter(builder, extensionReceiver) + } + + builder.append(declaration.name) + if (data && isRealExpect) builder.append(MangleConstant.EXPECT_MARK) + } + + override fun visitField(declaration: IrField, data: Boolean) = + declaration.mangleSimpleDeclaration(MangleConstant.FIELD_PREFIX, data, declaration.name.asString()) + + override fun visitEnumEntry(declaration: IrEnumEntry, data: Boolean) { + declaration.mangleSimpleDeclaration(MangleConstant.ENUM_ENTRY_PREFIX, data, declaration.name.asString()) + if (data && isRealExpect) builder.append(MangleConstant.EXPECT_MARK) + } + + override fun visitTypeAlias(declaration: IrTypeAlias, data: Boolean) = + declaration.mangleSimpleDeclaration(MangleConstant.TYPE_ALIAS_PREFIX, data, declaration.name.asString()) + + override fun visitTypeParameter(declaration: IrTypeParameter, data: Boolean) { + addPrefix(MangleConstant.TYPE_PARAM_PREFIX, data) + declaration.effectiveParent().accept(this, data) + + builder.append(MangleConstant.TYPE_PARAM_INDEX_PREFIX) + builder.append(declaration.index) + } + + override fun visitSimpleFunction(declaration: IrSimpleFunction, data: Boolean) { + + isRealExpect = isRealExpect or declaration.isExpect + + declaration.platformSpecificFunctionName?.let { + builder.append(it) + return + } + + val container = declaration.correspondingPropertySymbol?.owner ?: declaration + + declaration.mangleFunction(false, data, container) + } + + override fun visitConstructor(declaration: IrConstructor, data: Boolean) = declaration.mangleFunction(true, data, declaration) +} diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/mangleUtils.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/mangleUtils.kt new file mode 100644 index 00000000000..b38b7b00c8d --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/mangle/mangleUtils.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.common.serialization.mangle + +import org.jetbrains.kotlin.name.FqName + +internal fun Collection.collect(builder: StringBuilder, params: MangleConstant, collect: StringBuilder.(T) -> Unit) { + var first = true + + builder.append(params.prefix) + + for (e in this) { + if (first) { + first = false + } else { + builder.append(params.separator) + } + + builder.collect(e) + } + + builder.append(params.suffix) +} + +internal val publishedApiAnnotation = FqName("kotlin.PublishedApi") diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsMangler.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsMangler.kt index 8719b92ec4e..c9e66c01b76 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsMangler.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsMangler.kt @@ -5,25 +5,63 @@ package org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir -import org.jetbrains.kotlin.backend.common.serialization.KotlinManglerImpl -import org.jetbrains.kotlin.ir.declarations.IrTypeParameter -import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.util.isInlined +import org.jetbrains.kotlin.backend.common.serialization.mangle.KotlinExportChecker +import org.jetbrains.kotlin.backend.common.serialization.mangle.KotlinMangleComputer +import org.jetbrains.kotlin.backend.common.serialization.mangle.classic.ClassicExportChecker +import org.jetbrains.kotlin.backend.common.serialization.mangle.classic.ClassicKotlinManglerImpl +import org.jetbrains.kotlin.backend.common.serialization.mangle.classic.ClassicMangleComputer +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.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.ir.declarations.IrDeclaration -abstract class AbstractJsMangler : KotlinManglerImpl() { - override val IrType.isInlined: Boolean - get() = this.isInlined() +abstract class AbstractJsManglerIr : IrBasedKotlinManglerImpl() { + + companion object { + private val exportChecker = JsIrExportChecker() + } + + private class JsIrExportChecker : IrExportCheckerVisitor() { + override fun IrDeclaration.isPlatformSpecificExported() = false + } + + private class JsIrManglerComputer(builder: StringBuilder) : IrMangleComputer(builder) { + override fun copy(): IrMangleComputer = JsIrManglerComputer(builder) + } + + override fun getExportChecker(): KotlinExportChecker = exportChecker + + override fun getMangleComputer(prefix: String): KotlinMangleComputer { + return JsIrManglerComputer(StringBuilder(256)) + } } -object JsMangler : AbstractJsMangler() +object JsManglerIr : AbstractJsManglerIr() + +abstract class AbstractJsDescriptorMangler : DescriptorBasedKotlinManglerImpl() { + + companion object { + private val exportChecker = JsDescriptorExportChecker() + } + + private class JsDescriptorExportChecker : DescriptorExportCheckerVisitor() { + override fun DeclarationDescriptor.isPlatformSpecificExported() = false + } + + private class JsDescriptorManglerComputer(builder: StringBuilder, prefix: String) : DescriptorMangleComputer(builder, prefix) { + override fun copy(): DescriptorMangleComputer = JsDescriptorManglerComputer(builder, specialPrefix) + } + + override fun getExportChecker(): KotlinExportChecker = exportChecker + + override fun getMangleComputer(prefix: String): KotlinMangleComputer { + return JsDescriptorManglerComputer(StringBuilder(256), prefix) + } +} -/* - * JsManglerForBE is a special verison of kotlin mangler used in case when IR is not completely correct from Type Parameter perspective. - * I.e. usage of TypeParameter is not in TP's container. It's acceptable if only required to distinguish declaration somehow. - */ -object JsManglerForBE : AbstractJsMangler() { - - override fun mangleTypeParameter(typeParameter: IrTypeParameter, typeParameterNamer: (IrTypeParameter) -> String): String = - typeParameter.name.asString() -} \ No newline at end of file +object JsManglerDesc : AbstractJsDescriptorMangler() diff --git a/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/ir/backend/jvm/serialization/JvmMangler.kt b/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/ir/backend/jvm/serialization/JvmMangler.kt index 3dc8664ee1f..30ed9771396 100644 --- a/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/ir/backend/jvm/serialization/JvmMangler.kt +++ b/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/ir/backend/jvm/serialization/JvmMangler.kt @@ -5,13 +5,74 @@ package org.jetbrains.kotlin.ir.backend.jvm.serialization -import org.jetbrains.kotlin.backend.common.serialization.KotlinManglerImpl -import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.util.isInlined +import org.jetbrains.kotlin.backend.common.serialization.mangle.KotlinExportChecker +import org.jetbrains.kotlin.backend.common.serialization.mangle.KotlinMangleComputer +import org.jetbrains.kotlin.backend.common.serialization.mangle.classic.ClassicExportChecker +import org.jetbrains.kotlin.backend.common.serialization.mangle.classic.ClassicKotlinManglerImpl +import org.jetbrains.kotlin.backend.common.serialization.mangle.classic.ClassicMangleComputer +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.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.idea.MainFunctionDetector +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.load.java.lazy.descriptors.isJavaField -// Copied from JsMangler for now -object JvmMangler : KotlinManglerImpl() { +abstract class AbstractJvmManglerIr : IrBasedKotlinManglerImpl() { - override val IrType.isInlined: Boolean - get() = this.isInlined() + companion object { + private val exportChecker = JvmIrExportChecker() + } + + private class JvmIrExportChecker : IrExportCheckerVisitor() { + override fun IrDeclaration.isPlatformSpecificExported() = false + } + + private class JvmIrManglerComputer(builder: StringBuilder) : IrMangleComputer(builder) { + override fun copy(): IrMangleComputer = JvmIrManglerComputer(builder) + } + + override fun getExportChecker(): KotlinExportChecker = exportChecker + + override fun getMangleComputer(prefix: String): KotlinMangleComputer { + return JvmIrManglerComputer(StringBuilder(256)) + } } + +object JvmManglerIr : AbstractJvmManglerIr() + +abstract class AbstractJvmDescriptorMangler(private val mainDetector: MainFunctionDetector?) : DescriptorBasedKotlinManglerImpl() { + + companion object { + private val exportChecker = JvmDescriptorExportChecker() + } + + private class JvmDescriptorExportChecker : DescriptorExportCheckerVisitor() { + override fun DeclarationDescriptor.isPlatformSpecificExported() = false + } + + private class JvmDescriptorManglerComputer(builder: StringBuilder, prefix: String, private val mainDetector: MainFunctionDetector?) : + DescriptorMangleComputer(builder, prefix) { + override fun copy(): DescriptorMangleComputer = JvmDescriptorManglerComputer(builder, specialPrefix, mainDetector) + + private fun isMainFunction(descriptor: FunctionDescriptor): Boolean = mainDetector?.isMain(descriptor) ?: false + + override fun FunctionDescriptor.platformSpecificSuffix(): String? { + return if (isMainFunction(this)) { + return source.containingFile.name + } else null + } + } + + override fun getExportChecker(): KotlinExportChecker = exportChecker + + override fun getMangleComputer(prefix: String): KotlinMangleComputer { + return JvmDescriptorManglerComputer(StringBuilder(256), prefix, mainDetector) + } +} + +class JvmManglerDesc(mainDetector: MainFunctionDetector? = null) : AbstractJvmDescriptorMangler(mainDetector) \ No newline at end of file