diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt index e56d1c6e336..f1227e5de02 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt @@ -57,6 +57,7 @@ import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.backend.Fir2IrConverter import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendClassResolver import org.jetbrains.kotlin.fir.backend.jvm.FirJvmClassCodegen +import org.jetbrains.kotlin.fir.backend.jvm.FirJvmKotlinMangler import org.jetbrains.kotlin.fir.builder.RawFirBuilder import org.jetbrains.kotlin.fir.extensions.BunchOfRegisteredExtensions import org.jetbrains.kotlin.fir.extensions.extensionService @@ -354,7 +355,8 @@ object KotlinToJVMBytecodeCompiler { Fir2IrConverter.createModuleFragment( session, resolveTransformer.scopeSession, firFiles, moduleConfiguration.languageVersionSettings, signaturer = signaturer, - generatorExtensions = JvmGeneratorExtensions() + generatorExtensions = JvmGeneratorExtensions(), + mangler = FirJvmKotlinMangler(session) ) val dummyBindingContext = NoScopeRecordCliBindingTrace().bindingContext diff --git a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmKotlinMangler.kt b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmKotlinMangler.kt new file mode 100644 index 00000000000..6603a47fc78 --- /dev/null +++ b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmKotlinMangler.kt @@ -0,0 +1,37 @@ +/* + * 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.fir.backend.jvm + +import org.jetbrains.kotlin.backend.common.serialization.mangle.* +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.FirDeclaration +import org.jetbrains.kotlin.fir.signaturer.FirMangler + +class FirJvmKotlinMangler(private val session: FirSession) : AbstractKotlinMangler(), FirMangler { + + override val FirDeclaration.mangleString: String + get() = getMangleComputer(MangleMode.FULL).computeMangle(this) + + override val FirDeclaration.signatureString: String + get() = getMangleComputer(MangleMode.SIGNATURE).computeMangle(this) + + override val FirDeclaration.fqnString: String + get() = getMangleComputer(MangleMode.FQNAME).computeMangle(this) + + override fun FirDeclaration.isExported(): Boolean = true + + override fun getExportChecker(): KotlinExportChecker { + return object : KotlinExportChecker { + override fun check(declaration: FirDeclaration, type: SpecialDeclarationType): Boolean = true + + override fun FirDeclaration.isPlatformSpecificExported(): Boolean = true + } + } + + override fun getMangleComputer(mode: MangleMode): KotlinMangleComputer { + return FirJvmMangleComputer(StringBuilder(256), mode, session) + } +} \ No newline at end of file diff --git a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmMangleComputer.kt b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmMangleComputer.kt new file mode 100644 index 00000000000..c188b745934 --- /dev/null +++ b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmMangleComputer.kt @@ -0,0 +1,281 @@ +/* + * 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.fir.backend.jvm + +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.MangleMode +import org.jetbrains.kotlin.backend.common.serialization.mangle.collectForMangler +import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.render +import org.jetbrains.kotlin.fir.resolve.firSymbolProvider +import org.jetbrains.kotlin.fir.resolve.toSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol +import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.fir.visitors.FirVisitor +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty +import java.lang.IllegalStateException + +open class FirJvmMangleComputer( + private val builder: StringBuilder, + private val mode: MangleMode, + private val session: FirSession +) : FirVisitor(), KotlinMangleComputer { + + private val typeParameterContainer = ArrayList(4) + + private var isRealExpect = false + + open fun FirFunction<*>.platformSpecificFunctionName(): String? = null + + open fun FirFunction<*>.specialValueParamPrefix(param: FirValueParameter): String = "" + + private fun addReturnType(): Boolean = false + + override fun copy(newMode: MangleMode): FirJvmMangleComputer = + FirJvmMangleComputer(builder, newMode, session) + + private fun StringBuilder.appendName(s: String) { + if (mode.fqn) { + append(s) + } + } + + private fun StringBuilder.appendName(c: Char) { + if (mode.fqn) { + append(c) + } + } + + private fun StringBuilder.appendSignature(s: String) { + if (mode.signature) { + append(s) + } + } + + private fun StringBuilder.appendSignature(c: Char) { + if (mode.signature) { + append(c) + } + } + + private fun StringBuilder.appendSignature(i: Int) { + if (mode.signature) { + append(i) + } + } + + private fun FirDeclaration.visitParent() { + val (parentPackageFqName, parentClassId) = when (this) { + is FirCallableDeclaration<*> -> this.symbol.callableId.let { it.packageName to it.classId } + is FirClassLikeDeclaration<*> -> this.symbol.classId.let { it.packageFqName to it.outerClassId } + else -> return + } + if (parentClassId != null && !parentClassId.isLocal) { + val parentClass = session.firSymbolProvider.getClassLikeSymbolByFqName(parentClassId)?.fir as? FirRegularClass + ?: throw AssertionError("Attempt to find parent for probably-local declaration!") + parentClass.accept(this@FirJvmMangleComputer, false) + } else if (parentClassId == null && !parentPackageFqName.isRoot) { + builder.appendName(parentPackageFqName.asString()) + } + } + + private fun FirDeclaration.mangleSimpleDeclaration(name: String) { + val l = builder.length + visitParent() + + if (builder.length != l) { + builder.appendName(MangleConstant.FQN_SEPARATOR) + } + + builder.appendName(name) + } + + private fun FirFunction<*>.mangleFunction(isCtor: Boolean, isStatic: Boolean, container: FirDeclaration) { + + isRealExpect = isRealExpect || (this as? FirMemberDeclaration)?.isExpect == true + + if (container is FirMemberDeclaration) { + typeParameterContainer.add(container) + } + visitParent() + + builder.appendName(MangleConstant.FUNCTION_NAME_PREFIX) + + platformSpecificFunctionName()?.let { + builder.append(it) + return + } + + val name = (this as? FirSimpleFunction)?.name ?: Name.special("") + builder.append(name.asString()) + + mangleSignature(isCtor, isStatic) + } + + private fun FirFunction<*>.mangleSignature(isCtor: Boolean, isStatic: Boolean) { + if (!mode.signature) { + return + } + + if (isStatic) { + builder.appendSignature(MangleConstant.STATIC_MEMBER_MARK) + } + + receiverTypeRef?.let { + builder.appendSignature(MangleConstant.EXTENSION_RECEIVER_PREFIX) + mangleType(builder, it.coneTypeUnsafe()) + } + + valueParameters.collectForMangler(builder, MangleConstant.VALUE_PARAMETERS) { + appendSignature(specialValueParamPrefix(it)) + mangleValueParameter(this, it) + } + typeParameters.filterIsInstance().withIndex().toList() + .collectForMangler(builder, MangleConstant.TYPE_PARAMETERS) { (index, typeParameter) -> + mangleTypeParameter(this, typeParameter, index) + } + + if (!isCtor && !returnTypeRef.isUnit && addReturnType()) { + mangleType(builder, returnTypeRef.coneTypeUnsafe()) + } + } + + private fun FirTypeParameter.effectiveParent(): FirMemberDeclaration { + for (parent in typeParameterContainer) { + if (this in parent.typeParameters) { + return parent + } + } + throw IllegalStateException("Should not be here!") + } + + private fun mangleValueParameter(vpBuilder: StringBuilder, param: FirValueParameter) { + mangleType(vpBuilder, param.returnTypeRef.coneTypeUnsafe()) + + if (param.isVararg) { + vpBuilder.appendSignature(MangleConstant.VAR_ARG_MARK) + } + } + + private fun mangleTypeParameter(tpBuilder: StringBuilder, param: FirTypeParameter, index: Int) { + tpBuilder.appendSignature(index) + tpBuilder.appendSignature(MangleConstant.UPPER_BOUND_SEPARATOR) + + param.bounds.map { it.coneTypeUnsafe() }.collectForMangler(tpBuilder, MangleConstant.UPPER_BOUNDS) { + mangleType(this, it) + } + } + + private fun StringBuilder.mangleTypeParameterReference(typeParameter: FirTypeParameter) { + val parent = typeParameter.effectiveParent() + val ci = typeParameterContainer.indexOf(parent) + require(ci >= 0) { "No type container found for ${typeParameter.render()}" } + appendSignature(ci) + appendSignature(MangleConstant.INDEX_SEPARATOR) + appendSignature(parent.typeParameters.indexOf(typeParameter)) + } + + private fun mangleType(tBuilder: StringBuilder, type: ConeKotlinType) { + when (type) { + is ConeLookupTagBasedType -> { + when (val symbol = type.lookupTag.toSymbol(session)) { + is FirClassSymbol -> symbol.fir.accept(copy(MangleMode.FQNAME), false) + is FirTypeParameterSymbol -> tBuilder.mangleTypeParameterReference(symbol.fir) + } + + type.typeArguments.asList().ifNotEmpty { + collectForMangler(tBuilder, MangleConstant.TYPE_ARGUMENTS) { arg -> + when (arg) { + is ConeStarProjection -> appendSignature(MangleConstant.STAR_MARK) + is ConeKotlinTypeProjection -> { + if (arg.kind != ProjectionKind.INVARIANT) { + appendSignature(arg.kind.name.toLowerCase()) + appendSignature(MangleConstant.VARIANCE_SEPARATOR) + } + + mangleType(this, arg.type) + } + } + } + } + + if (type.isMarkedNullable) { + tBuilder.appendSignature(MangleConstant.Q_MARK) + } + } + is ConeFlexibleType -> { + // TODO: is that correct way to mangle flexible type? + with(MangleConstant.FLEXIBLE_TYPE) { + tBuilder.appendSignature(prefix) + mangleType(tBuilder, type.lowerBound) + tBuilder.appendSignature(separator) + mangleType(tBuilder, type.upperBound) + tBuilder.appendSignature(suffix) + } + } + else -> error("Unexpected type $type") + } + } + + override fun visitElement(element: FirElement, data: Boolean) = error("unexpected element ${element.render()}") + + override fun visitRegularClass(regularClass: FirRegularClass, data: Boolean) { + isRealExpect = isRealExpect or regularClass.isExpect + typeParameterContainer.add(regularClass) + regularClass.mangleSimpleDeclaration(regularClass.name.asString()) + } + + override fun visitProperty(property: FirProperty, data: Boolean) { + isRealExpect = isRealExpect or property.isExpect + typeParameterContainer.add(property) + property.visitParent() + + val isStaticProperty = property.isStatic + if (isStaticProperty) { + builder.appendSignature(MangleConstant.STATIC_MEMBER_MARK) + } + + property.receiverTypeRef?.let { + builder.appendSignature(MangleConstant.EXTENSION_RECEIVER_PREFIX) + mangleType(builder, it.coneTypeUnsafe()) + } + + property.typeParameters.withIndex().toList().collectForMangler(builder, MangleConstant.TYPE_PARAMETERS) { (index, typeParameter) -> + mangleTypeParameter(this, typeParameter, index) + } + + builder.append(property.name.asString()) + } + + override fun visitField(field: FirField, data: Boolean) = + field.mangleSimpleDeclaration(field.name.asString()) + + override fun visitEnumEntry(enumEntry: FirEnumEntry, data: Boolean) { + enumEntry.mangleSimpleDeclaration(enumEntry.name.asString()) + } + + override fun visitTypeAlias(typeAlias: FirTypeAlias, data: Boolean) = + typeAlias.mangleSimpleDeclaration(typeAlias.name.asString()) + + override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: Boolean) { + isRealExpect = isRealExpect || simpleFunction.isExpect + val isStatic = simpleFunction.isStatic + simpleFunction.mangleFunction(false, isStatic, simpleFunction) + } + + override fun visitConstructor(constructor: FirConstructor, data: Boolean) = + constructor.mangleFunction(isCtor = true, isStatic = false, constructor) + + override fun computeMangle(declaration: FirDeclaration): String { + declaration.accept(this, true) + return builder.toString() + } +} diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt index f2335331422..3697f4260de 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.backend import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.signaturer.FirBasedSignatureComposer +import org.jetbrains.kotlin.fir.signaturer.FirMangler import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.util.SymbolTable @@ -15,11 +16,12 @@ class Fir2IrComponentsStorage( override val session: FirSession, override val scopeSession: ScopeSession, override val symbolTable: SymbolTable, - override val irBuiltIns: IrBuiltIns + override val irBuiltIns: IrBuiltIns, + mangler: FirMangler ) : Fir2IrComponents { override lateinit var classifierStorage: Fir2IrClassifierStorage override lateinit var declarationStorage: Fir2IrDeclarationStorage override lateinit var typeConverter: Fir2IrTypeConverter - override val signatureComposer = FirBasedSignatureComposer() + override val signatureComposer = FirBasedSignatureComposer(mangler) } \ No newline at end of file diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt index 427fe7dfd05..dc1890964a1 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.signaturer.FirMangler import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl @@ -165,7 +166,8 @@ class Fir2IrConverter( languageVersionSettings: LanguageVersionSettings, fakeOverrideMode: FakeOverrideMode = FakeOverrideMode.NORMAL, signaturer: IdSignatureComposer, - generatorExtensions: GeneratorExtensions + generatorExtensions: GeneratorExtensions, + mangler: FirMangler ): Fir2IrResult { val moduleDescriptor = FirModuleDescriptor(session) val symbolTable = SymbolTable(signaturer) @@ -176,7 +178,7 @@ class Fir2IrConverter( val builtIns = IrBuiltIns(moduleDescriptor.builtIns, typeTranslator, symbolTable) BuiltinSymbolsBase(builtIns, moduleDescriptor.builtIns, symbolTable) val sourceManager = PsiSourceManager() - val components = Fir2IrComponentsStorage(session, scopeSession, symbolTable, builtIns) + val components = Fir2IrComponentsStorage(session, scopeSession, symbolTable, builtIns, mangler) val declarationStorage = Fir2IrDeclarationStorage(components, moduleDescriptor) val classifierStorage = Fir2IrClassifierStorage(components) val typeConverter = Fir2IrTypeConverter(components) diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/signaturer/FirBasedSignatureComposer.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/signaturer/FirBasedSignatureComposer.kt index 50491be30cc..7ea914e359c 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/signaturer/FirBasedSignatureComposer.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/signaturer/FirBasedSignatureComposer.kt @@ -16,8 +16,8 @@ import org.jetbrains.kotlin.ir.util.IdSignature import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name -class FirBasedSignatureComposer : Fir2IrSignatureComposer { - class SignatureBuilder : FirVisitorVoid() { +class FirBasedSignatureComposer(private val mangler: FirMangler) : Fir2IrSignatureComposer { + inner class SignatureBuilder : FirVisitorVoid() { var hashId: Long? = null var mask = 0L @@ -35,14 +35,17 @@ class FirBasedSignatureComposer : Fir2IrSignatureComposer { } override fun visitConstructor(constructor: FirConstructor) { + hashId = mangler.run { constructor.signatureMangle } setExpected(constructor.isExpect) } override fun visitSimpleFunction(simpleFunction: FirSimpleFunction) { + hashId = mangler.run { simpleFunction.signatureMangle } setExpected(simpleFunction.isExpect) } override fun visitProperty(property: FirProperty) { + hashId = mangler.run { property.signatureMangle } setExpected(property.isExpect) } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/signaturer/FirMangler.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/signaturer/FirMangler.kt new file mode 100644 index 00000000000..a69a36f9f70 --- /dev/null +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/signaturer/FirMangler.kt @@ -0,0 +1,14 @@ +/* + * 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.fir.signaturer + +import org.jetbrains.kotlin.fir.declarations.FirDeclaration +import org.jetbrains.kotlin.ir.util.KotlinMangler + +interface FirMangler : KotlinMangler { + override val manglerName: String + get() = "Fir" +} \ No newline at end of file diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/AbstractFir2IrTextTest.kt b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/AbstractFir2IrTextTest.kt index b8dd253076f..cd2e9cc9845 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/AbstractFir2IrTextTest.kt +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/AbstractFir2IrTextTest.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmGeneratorExtensions import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.fir.backend.Fir2IrConverter +import org.jetbrains.kotlin.fir.backend.jvm.FirJvmKotlinMangler import org.jetbrains.kotlin.fir.builder.RawFirBuilder import org.jetbrains.kotlin.fir.resolve.firProvider import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl @@ -88,7 +89,8 @@ abstract class AbstractFir2IrTextTest : AbstractIrTextTestCase() { myEnvironment.configuration.languageVersionSettings, signaturer = signaturer, // TODO: differentiate JVM resolve from other targets, such as JS resolve. - generatorExtensions = JvmGeneratorExtensions(generateFacades = false) + generatorExtensions = JvmGeneratorExtensions(generateFacades = false), + mangler = FirJvmKotlinMangler(session) ).irModuleFragment } } \ No newline at end of file diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/GenerationUtils.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/GenerationUtils.kt index 29c5900869c..890994d8400 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/GenerationUtils.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/GenerationUtils.kt @@ -44,6 +44,7 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.fir.backend.Fir2IrConverter import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendClassResolver import org.jetbrains.kotlin.fir.backend.jvm.FirJvmClassCodegen +import org.jetbrains.kotlin.fir.backend.jvm.FirJvmKotlinMangler import org.jetbrains.kotlin.fir.builder.RawFirBuilder import org.jetbrains.kotlin.fir.createSession import org.jetbrains.kotlin.fir.resolve.firProvider @@ -145,7 +146,8 @@ object GenerationUtils { configuration.languageVersionSettings, signaturer = IdSignatureDescriptor(JvmManglerDesc()), // TODO: differentiate JVM resolve from other targets, such as JS resolve. - generatorExtensions = JvmGeneratorExtensions() + generatorExtensions = JvmGeneratorExtensions(), + mangler = FirJvmKotlinMangler(session) ) val dummyBindingContext = NoScopeRecordCliBindingTrace().bindingContext