[FIR2IR] Cache functions/properties both by symbol & signature
This commit is contained in:
@@ -5,9 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.backend
|
||||
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirConstructor
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.util.parentClassOrNull
|
||||
@@ -99,10 +97,9 @@ class Fir2IrConversionScope {
|
||||
fun returnTarget(expression: FirReturnExpression, declarationStorage: Fir2IrDeclarationStorage): IrFunction {
|
||||
val firTarget = expression.target.labeledElement
|
||||
val irTarget = (firTarget as? FirFunction)?.let {
|
||||
if (it is FirConstructor) {
|
||||
declarationStorage.getCachedIrConstructor(it)
|
||||
} else {
|
||||
declarationStorage.getCachedIrFunction(it)
|
||||
when (it) {
|
||||
is FirConstructor -> declarationStorage.getCachedIrConstructor(it)
|
||||
else -> declarationStorage.getCachedIrFunction(it)
|
||||
}
|
||||
}
|
||||
for (potentialTarget in functionStack.asReversed()) {
|
||||
|
||||
@@ -297,9 +297,7 @@ class Fir2IrConverter(
|
||||
// Necessary call to generate built-in IR classes
|
||||
externalDependenciesGenerator.generateUnboundSymbolsAsDependencies()
|
||||
classifierStorage.preCacheBuiltinClasses()
|
||||
val fakeOverrideGenerator = FakeOverrideGenerator(
|
||||
session, scopeSession, classifierStorage, declarationStorage, conversionScope
|
||||
)
|
||||
val fakeOverrideGenerator = FakeOverrideGenerator(components, conversionScope)
|
||||
components.fakeOverrideGenerator = fakeOverrideGenerator
|
||||
val callGenerator = CallAndReferenceGenerator(components, fir2irVisitor, conversionScope)
|
||||
components.callGenerator = callGenerator
|
||||
|
||||
+69
-40
@@ -364,11 +364,24 @@ class Fir2IrDeclarationStorage(
|
||||
return this
|
||||
}
|
||||
|
||||
fun getCachedIrFunction(function: FirFunction<*>): IrSimpleFunction? {
|
||||
return if (function !is FirSimpleFunction || function.visibility == Visibilities.Local) {
|
||||
fun getCachedIrFunction(function: FirFunction<*>): IrSimpleFunction? =
|
||||
if (function is FirSimpleFunction) getCachedIrFunction(function)
|
||||
else localStorage.getLocalFunction(function)
|
||||
|
||||
fun getCachedIrFunction(
|
||||
function: FirSimpleFunction,
|
||||
signatureCalculator: (FirSimpleFunction) -> IdSignature? = { null }
|
||||
): IrSimpleFunction? {
|
||||
return if (function.visibility == Visibilities.Local) {
|
||||
localStorage.getLocalFunction(function)
|
||||
} else {
|
||||
functionCache[function]
|
||||
functionCache[function] ?: signatureCalculator(function)?.let { signature ->
|
||||
symbolTable.referenceSimpleFunctionIfAny(signature)?.let { irFunctionSymbol ->
|
||||
val irFunction = irFunctionSymbol.owner
|
||||
functionCache[function] = irFunction
|
||||
irFunction
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,7 +407,7 @@ class Fir2IrDeclarationStorage(
|
||||
}
|
||||
|
||||
fun getOrCreateIrFunction(
|
||||
function: FirFunction<*>,
|
||||
function: FirSimpleFunction,
|
||||
irParent: IrDeclarationParent?,
|
||||
isLocal: Boolean = false,
|
||||
): IrSimpleFunction {
|
||||
@@ -792,7 +805,18 @@ class Fir2IrDeclarationStorage(
|
||||
}
|
||||
}
|
||||
|
||||
fun getCachedIrProperty(property: FirProperty): IrProperty? = propertyCache[property]
|
||||
fun getCachedIrProperty(
|
||||
property: FirProperty,
|
||||
signatureCalculator: (FirProperty) -> IdSignature? = { null }
|
||||
): IrProperty? {
|
||||
return propertyCache[property] ?: signatureCalculator(property)?.let { signature ->
|
||||
symbolTable.referencePropertyIfAny(signature)?.let { irPropertySymbol ->
|
||||
val irProperty = irPropertySymbol.owner
|
||||
propertyCache[property] = irProperty
|
||||
irProperty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun cacheDelegatedProperty(property: FirProperty, irProperty: IrProperty) {
|
||||
propertyCache[property] = irProperty
|
||||
@@ -808,11 +832,6 @@ class Fir2IrDeclarationStorage(
|
||||
return irField
|
||||
}
|
||||
|
||||
private fun getFirClassByFqName(classId: ClassId): FirClass<*>? {
|
||||
val declaration = firSymbolProvider.getClassLikeSymbolByFqName(classId)
|
||||
return declaration?.fir as? FirClass<*>
|
||||
}
|
||||
|
||||
private fun createIrField(
|
||||
field: FirField,
|
||||
origin: IrDeclarationOrigin = IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB
|
||||
@@ -1012,33 +1031,43 @@ class Fir2IrDeclarationStorage(
|
||||
|
||||
fun getIrFunctionSymbol(firFunctionSymbol: FirFunctionSymbol<*>): IrFunctionSymbol {
|
||||
return when (val firDeclaration = firFunctionSymbol.fir) {
|
||||
is FirSimpleFunction, is FirAnonymousFunction -> {
|
||||
is FirAnonymousFunction -> {
|
||||
getCachedIrFunction(firDeclaration)?.let { return it.symbol }
|
||||
val signature = signatureComposer.composeSignature(firDeclaration)
|
||||
val irParent = findIrParent(firDeclaration)
|
||||
val parentOrigin = (irParent as? IrDeclaration)?.origin ?: IrDeclarationOrigin.DEFINED
|
||||
val declarationOrigin = computeDeclarationOrigin(firFunctionSymbol, parentOrigin, irParent)
|
||||
createIrFunction(firDeclaration, irParent, origin = declarationOrigin).apply {
|
||||
setAndModifyParent(irParent)
|
||||
}.symbol
|
||||
}
|
||||
is FirSimpleFunction -> {
|
||||
val irParent by lazy { findIrParent(firDeclaration) }
|
||||
getCachedIrFunction(firDeclaration) {
|
||||
// Parent calculation provokes function calculation for some members from IrBuiltIns
|
||||
@Suppress("UNUSED_EXPRESSION") irParent
|
||||
signatureComposer.composeSignature(it)
|
||||
}?.let { return it.symbol }
|
||||
val parentOrigin = (irParent as? IrDeclaration)?.origin ?: IrDeclarationOrigin.DEFINED
|
||||
|
||||
if (signature != null) {
|
||||
symbolTable.referenceSimpleFunctionIfAny(signature)?.let { irFunctionSymbol ->
|
||||
val irFunction = irFunctionSymbol.owner
|
||||
functionCache[firDeclaration] = irFunction
|
||||
return irFunctionSymbol
|
||||
// TODO: package fragment members (?)
|
||||
val parent = irParent
|
||||
if (parent is Fir2IrLazyClass) {
|
||||
assert(parentOrigin != IrDeclarationOrigin.DEFINED) {
|
||||
"Should not have reference to public API uncached simple function from source code"
|
||||
}
|
||||
// TODO: package fragment members (?)
|
||||
if (firDeclaration is FirSimpleFunction && irParent is Fir2IrLazyClass) {
|
||||
assert(parentOrigin != IrDeclarationOrigin.DEFINED) {
|
||||
"Should not have reference to public API uncached simple function from source code"
|
||||
}
|
||||
val signature = signatureComposer.composeSignature(firDeclaration)
|
||||
if (signature != null) {
|
||||
val symbol = Fir2IrSimpleFunctionSymbol(signature, firDeclaration.containerSource)
|
||||
val irFunction = firDeclaration.convertWithOffsets { startOffset, endOffset ->
|
||||
symbolTable.declareSimpleFunction(signature, { symbol }) {
|
||||
val isFakeOverride =
|
||||
firFunctionSymbol is FirNamedFunctionSymbol && firFunctionSymbol.fir.isSubstitutionOverride &&
|
||||
firFunctionSymbol.dispatchReceiverClassOrNull() != firFunctionSymbol.originalForSubstitutionOverride?.dispatchReceiverClassOrNull()
|
||||
firFunctionSymbol.dispatchReceiverClassOrNull() !=
|
||||
firFunctionSymbol.originalForSubstitutionOverride?.dispatchReceiverClassOrNull()
|
||||
Fir2IrLazySimpleFunction(
|
||||
components, startOffset, endOffset, parentOrigin, firDeclaration, irParent.fir, symbol, isFakeOverride
|
||||
components, startOffset, endOffset, parentOrigin, firDeclaration, parent.fir, symbol, isFakeOverride
|
||||
).apply {
|
||||
parent = irParent
|
||||
this.parent = parent
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1078,24 +1107,24 @@ class Fir2IrDeclarationStorage(
|
||||
if (fir.isLocal) {
|
||||
return localStorage.getDelegatedProperty(fir)?.symbol ?: getIrVariableSymbol(fir)
|
||||
}
|
||||
propertyCache[fir]?.let { return it.symbol }
|
||||
val signature = signatureComposer.composeSignature(fir)
|
||||
val irParent = findIrParent(fir)
|
||||
val irParent by lazy { findIrParent(fir) }
|
||||
getCachedIrProperty(fir) {
|
||||
// Parent calculation provokes property calculation for some members from IrBuiltIns
|
||||
@Suppress("UNUSED_EXPRESSION") irParent
|
||||
signatureComposer.composeSignature(it)
|
||||
}?.let { return it.symbol }
|
||||
val parentOrigin = (irParent as? IrDeclaration)?.origin ?: IrDeclarationOrigin.DEFINED
|
||||
// TODO: Use computeDeclarationOrigin(firPropertySymbol, parentOrigin)
|
||||
// Currently many backend tests are failing
|
||||
val declarationOrigin = parentOrigin
|
||||
if (signature != null) {
|
||||
symbolTable.referencePropertyIfAny(signature)?.let { irPropertySymbol ->
|
||||
val irProperty = irPropertySymbol.owner
|
||||
propertyCache[fir] = irProperty
|
||||
return irPropertySymbol
|
||||
// TODO: package fragment members (?)
|
||||
val parent = irParent
|
||||
if (parent is Fir2IrLazyClass) {
|
||||
assert(parentOrigin != IrDeclarationOrigin.DEFINED) {
|
||||
"Should not have reference to public API uncached property from source code"
|
||||
}
|
||||
// TODO: package fragment members (?)
|
||||
if (irParent is Fir2IrLazyClass) {
|
||||
assert(parentOrigin != IrDeclarationOrigin.DEFINED) {
|
||||
"Should not have reference to public API uncached property from source code"
|
||||
}
|
||||
val signature = signatureComposer.composeSignature(fir)
|
||||
if (signature != null) {
|
||||
val symbol = Fir2IrPropertySymbol(signature, fir.containerSource)
|
||||
val irProperty = fir.convertWithOffsets { startOffset, endOffset ->
|
||||
symbolTable.declareProperty(signature, { symbol }) {
|
||||
@@ -1103,9 +1132,9 @@ class Fir2IrDeclarationStorage(
|
||||
firPropertySymbol.fir.isSubstitutionOverride &&
|
||||
firPropertySymbol.dispatchReceiverClassOrNull() != firPropertySymbol.originalForSubstitutionOverride?.dispatchReceiverClassOrNull()
|
||||
Fir2IrLazyProperty(
|
||||
components, startOffset, endOffset, declarationOrigin, fir, irParent.fir, symbol, isFakeOverride
|
||||
components, startOffset, endOffset, declarationOrigin, fir, parent.fir, symbol, isFakeOverride
|
||||
).apply {
|
||||
parent = irParent
|
||||
this.parent = parent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-8
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.backend.*
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
|
||||
import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenFunctions
|
||||
@@ -28,15 +27,13 @@ import org.jetbrains.kotlin.ir.types.IrErrorType
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeProjection
|
||||
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||
import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
|
||||
|
||||
class FakeOverrideGenerator(
|
||||
private val session: FirSession,
|
||||
private val scopeSession: ScopeSession,
|
||||
private val classifierStorage: Fir2IrClassifierStorage,
|
||||
private val declarationStorage: Fir2IrDeclarationStorage,
|
||||
private val components: Fir2IrComponents,
|
||||
private val conversionScope: Fir2IrConversionScope
|
||||
) {
|
||||
) : Fir2IrComponents by components {
|
||||
|
||||
private val baseFunctionSymbols = mutableMapOf<IrFunction, List<FirNamedFunctionSymbol>>()
|
||||
private val basePropertySymbols = mutableMapOf<IrProperty, List<FirPropertySymbol>>()
|
||||
@@ -134,7 +131,7 @@ class FakeOverrideGenerator(
|
||||
irClass: IrClass,
|
||||
isLocal: Boolean,
|
||||
originalSymbol: FirCallableSymbol<*>,
|
||||
cachedIrDeclaration: (D) -> I?,
|
||||
cachedIrDeclaration: (D, (D) -> IdSignature?) -> I?,
|
||||
createIrDeclaration: (D, irParent: IrClass, thisReceiverOwner: IrClass?, origin: IrDeclarationOrigin, isLocal: Boolean) -> I,
|
||||
createFakeOverrideSymbol: (D, S) -> S,
|
||||
baseSymbols: MutableMap<I, List<S>>,
|
||||
@@ -156,7 +153,13 @@ class FakeOverrideGenerator(
|
||||
if (originalSymbol.fir.origin.fromSupertypes && originalSymbol.dispatchReceiverClassOrNull() == classLookupTag) {
|
||||
// Substitution case
|
||||
// NB: see comment above about substituted function' parent
|
||||
val irDeclaration = cachedIrDeclaration(originalDeclaration)?.takeIf { it.parent == irClass }
|
||||
val irDeclaration = cachedIrDeclaration(originalDeclaration) {
|
||||
// Sometimes we can have clashing here when FIR substitution/intersection override
|
||||
// have the same signature.
|
||||
// Now we avoid this problem by signature caching,
|
||||
// so both FIR overrides correspond to one IR fake override
|
||||
signatureComposer.composeSignature(originalDeclaration)
|
||||
}?.takeIf { it.parent == irClass }
|
||||
?: createIrDeclaration(
|
||||
originalDeclaration, irClass,
|
||||
declarationStorage.findIrParent(baseSymbol.fir) as? IrClass,
|
||||
|
||||
+5
@@ -410,6 +410,11 @@ public class FirCompileKotlinAgainstKotlinTestGenerated extends AbstractFirCompi
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/fir/AnonymousObjectInProperty.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ExistingSymbolInFakeOverride.kt")
|
||||
public void testExistingSymbolInFakeOverride() throws Exception {
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/fir/ExistingSymbolInFakeOverride.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("LibraryProperty.kt")
|
||||
public void testLibraryProperty() throws Exception {
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/fir/LibraryProperty.kt");
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// FILE: A.kt
|
||||
|
||||
interface KotlinMangler<D : Any> {
|
||||
val String.hashMangle: Long
|
||||
val D.fqnString: String
|
||||
val D.fqnMangle: Long get() = fqnString.hashMangle
|
||||
val manglerName: String
|
||||
|
||||
interface IrMangler : KotlinMangler<String> {
|
||||
override val manglerName: String
|
||||
get() = "Ir"
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractKotlinMangler<D : Any> : KotlinMangler<D> {
|
||||
override val String.hashMangle get() = 42L
|
||||
}
|
||||
|
||||
abstract class IrBasedKotlinManglerImpl : AbstractKotlinMangler<String>(), KotlinMangler.IrMangler {
|
||||
override val String.fqnString: String
|
||||
get() = this
|
||||
}
|
||||
|
||||
// FILE: B.kt
|
||||
|
||||
abstract class AbstractJvmManglerIr : IrBasedKotlinManglerImpl()
|
||||
|
||||
object JvmManglerIr : AbstractJvmManglerIr()
|
||||
|
||||
fun box() = "OK"
|
||||
+5
@@ -415,6 +415,11 @@ public class CompileKotlinAgainstKotlinTestGenerated extends AbstractCompileKotl
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/fir/AnonymousObjectInProperty.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ExistingSymbolInFakeOverride.kt")
|
||||
public void testExistingSymbolInFakeOverride() throws Exception {
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/fir/ExistingSymbolInFakeOverride.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("LibraryProperty.kt")
|
||||
public void testLibraryProperty() throws Exception {
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/fir/LibraryProperty.kt");
|
||||
|
||||
Generated
+5
@@ -410,6 +410,11 @@ public class IrCompileKotlinAgainstKotlinTestGenerated extends AbstractIrCompile
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/fir/AnonymousObjectInProperty.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ExistingSymbolInFakeOverride.kt")
|
||||
public void testExistingSymbolInFakeOverride() throws Exception {
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/fir/ExistingSymbolInFakeOverride.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("LibraryProperty.kt")
|
||||
public void testLibraryProperty() throws Exception {
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/fir/LibraryProperty.kt");
|
||||
|
||||
+5
@@ -410,6 +410,11 @@ public class JvmIrAgainstOldBoxTestGenerated extends AbstractJvmIrAgainstOldBoxT
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/fir/AnonymousObjectInProperty.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ExistingSymbolInFakeOverride.kt")
|
||||
public void testExistingSymbolInFakeOverride() throws Exception {
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/fir/ExistingSymbolInFakeOverride.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("LibraryProperty.kt")
|
||||
public void testLibraryProperty() throws Exception {
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/fir/LibraryProperty.kt");
|
||||
|
||||
+5
@@ -410,6 +410,11 @@ public class JvmOldAgainstIrBoxTestGenerated extends AbstractJvmOldAgainstIrBoxT
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/fir/AnonymousObjectInProperty.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("ExistingSymbolInFakeOverride.kt")
|
||||
public void testExistingSymbolInFakeOverride() throws Exception {
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/fir/ExistingSymbolInFakeOverride.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("LibraryProperty.kt")
|
||||
public void testLibraryProperty() throws Exception {
|
||||
runTest("compiler/testData/compileKotlinAgainstKotlin/fir/LibraryProperty.kt");
|
||||
|
||||
Reference in New Issue
Block a user