Introduce first version of FirJvmKotlinMangler & its parts

This commit is contained in:
Mikhail Glukhikh
2020-05-27 17:46:03 +03:00
parent a239604c24
commit 9ea69b4b3c
9 changed files with 354 additions and 9 deletions
@@ -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
@@ -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<FirDeclaration>(), 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<FirDeclaration> {
return object : KotlinExportChecker<FirDeclaration> {
override fun check(declaration: FirDeclaration, type: SpecialDeclarationType): Boolean = true
override fun FirDeclaration.isPlatformSpecificExported(): Boolean = true
}
}
override fun getMangleComputer(mode: MangleMode): KotlinMangleComputer<FirDeclaration> {
return FirJvmMangleComputer(StringBuilder(256), mode, session)
}
}
@@ -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<Unit, Boolean>(), KotlinMangleComputer<FirDeclaration> {
private val typeParameterContainer = ArrayList<FirMemberDeclaration>(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("<anonymous>")
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<FirTypeParameter>().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<ConeKotlinType>() }.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()
}
}
@@ -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)
}
@@ -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)
@@ -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)
}
}
@@ -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<FirDeclaration> {
override val manglerName: String
get() = "Fir"
}
@@ -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
}
}
@@ -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