Skip to content

Commit

Permalink
[K/N] Rework naming of function reference classes
Browse files Browse the repository at this point in the history
^KT-72738 Fixed
  • Loading branch information
kunyavskiy authored and Space Team committed Nov 7, 2024
1 parent 3773ffe commit adb2912
Show file tree
Hide file tree
Showing 13 changed files with 114 additions and 154 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,17 @@ abstract class InventNamesForLocalClasses(private val shouldIncludeVariableName:
}

override fun visitField(declaration: IrField, data: NameBuilder) {
// Skip field name because the name of the property is already there.
declaration.acceptChildren(this, data.copy(isLocal = true))
if (data.parent == null && declaration.correspondingPropertySymbol == null) {
// Normally this shouldn't happen, but it can because of previous lowerings and plugins
// If we add nothing to the name, this would crash, as there would be a local declaration,
// which is not inside anything. But if we are inside any declaration.
// But if we are inside any declaration, let's just skip.
// Syntetic field name is probably not useful anyway.
visitDeclaration(declaration, data)
} else {
// Skip the field name because the name of the property is already there.
declaration.acceptChildren(this, data.copy(isLocal = true))
}
}

override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer, data: NameBuilder) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ internal class FileLowerState {
private var coroutineCount = 0
private var cStubCount = 0

fun getFunctionReferenceImplUniqueName(targetFunction: IrFunction): String =
getFunctionReferenceImplUniqueName("${targetFunction.name}\$FUNCTION_REFERENCE\$")

fun getCoroutineImplUniqueName(function: IrFunction): String =
"${function.name}COROUTINE\$${coroutineCount++}"

Expand Down Expand Up @@ -74,15 +71,6 @@ internal class NativeGenerationState(
val liveVariablesAtSuspensionPoints = mutableMapOf<IrSuspensionPoint, List<IrVariable>>()
val visibleVariablesAtSuspensionPoints = mutableMapOf<IrSuspensionPoint, List<IrVariable>>()

private val localClassNames = mutableMapOf<IrAttributeContainer, String>()
fun getLocalClassName(container: IrAttributeContainer): String? = localClassNames[container.attributeOwnerId]
fun putLocalClassName(container: IrAttributeContainer, name: String) {
localClassNames[container.attributeOwnerId] = name
}
fun copyLocalClassName(source: IrAttributeContainer, destination: IrAttributeContainer) {
getLocalClassName(source)?.let { name -> putLocalClassName(destination, name) }
}

lateinit var fileLowerState: FileLowerState

val producedLlvmModuleContainsStdlib get() = llvmModuleSpecification.containsModule(context.stdlibModule)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,12 +319,6 @@ private val functionReferencePhase = createFileLoweringPhase(
name = "FunctionReference",
)

private val buildNamesForFunctionReferenceImpls = createFileLoweringPhase(
lowering = ::FunctionReferenceImplNamesBuilder,
name = "BuildNamesForFunctionReferenceImpls",
prerequisite = setOf(functionReferencePhase, localFunctionsPhase)
)

private val staticFunctionReferenceOptimizationPhase = createFileLoweringPhase(
lowering = ::StaticFunctionReferenceOptimization,
name = "StaticFunctionReferenceOptimization",
Expand Down Expand Up @@ -573,7 +567,6 @@ internal fun KonanConfig.getLoweringsAfterInlining(): LoweringList = listOfNotNu
stripTypeAliasDeclarationsPhase,
assertionRemoverPhase,
provisionalFunctionExpressionPhase,
inventNamesForLocalClasses,
functionReferencePhase,
postInlinePhase,
testProcessorPhase.takeIf { this.configuration.getNotNull(KonanConfigKeys.GENERATE_TEST_RUNNER) != TestRunnerKind.NONE },
Expand All @@ -586,8 +579,8 @@ internal fun KonanConfig.getLoweringsAfterInlining(): LoweringList = listOfNotNu
stringConcatenationTypeNarrowingPhase.takeIf { this.optimizationsEnabled },
enumConstructorsPhase,
initializersPhase,
inventNamesForLocalClasses,
localFunctionsPhase,
buildNamesForFunctionReferenceImpls,
volatilePhase,
tailrecPhase,
defaultParameterExtentPhase,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.backend.konan.ir.isArray
import org.jetbrains.kotlin.backend.konan.llvm.objcexport.WritableTypeInfoPointer
import org.jetbrains.kotlin.backend.konan.llvm.objcexport.generateWritableTypeInfoForSyntheticInterface
import org.jetbrains.kotlin.backend.konan.lower.FunctionReferenceLowering.Companion.isLoweredFunctionReference
import org.jetbrains.kotlin.backend.konan.lower.hasSyntheticNameToBeHiddenInReflection
import org.jetbrains.kotlin.backend.konan.lower.getObjectClassInstanceFunction
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.ir.declarations.*
Expand Down Expand Up @@ -590,17 +590,12 @@ internal class RTTIGenerator(
val flags: Int

when {
isLoweredFunctionReference(irClass) -> {
// TODO: might return null so use fallback here, to be fixed in KT-47194
relativeName = generationState.getLocalClassName(irClass) ?: generateDefaultRelativeName(irClass)
flags = 0 // Forbid to use package and relative names in KClass.[simpleName|qualifiedName].
}
irClass.isAnonymousObject -> {
relativeName = generationState.getLocalClassName(irClass)
irClass.hasSyntheticNameToBeHiddenInReflection -> {
relativeName = irClass.name.asString()
flags = 0 // Forbid to use package and relative names in KClass.[simpleName|qualifiedName].
}
irClass.isLocal -> {
relativeName = generationState.getLocalClassName(irClass)
relativeName = irClass.name.asString()
flags = TF_REFLECTION_SHOW_REL_NAME // Only allow relative name to be used in KClass.simpleName.
}
else -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.llvm.computeFullName
import org.jetbrains.kotlin.backend.konan.lower.FunctionReferenceLowering.Companion.isLoweredFunctionReference
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrElement
Expand All @@ -21,49 +20,15 @@ import org.jetbrains.kotlin.ir.builders.declarations.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.irAttribute
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.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.IrTransformer
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames

internal var IrClass.functionReferenceImplMethod: IrFunction? by irAttribute(followAttributeOwner = false)

internal class FunctionReferenceImplNamesBuilder(val generationState: NativeGenerationState) : FileLoweringPass {
private val fileLowerState = generationState.fileLowerState

override fun lower(irFile: IrFile) {
irFile.acceptChildrenVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}

override fun visitClass(declaration: IrClass) {
declaration.acceptChildrenVoid(this)

if (isLoweredFunctionReference(declaration)) {
val functionReferenceImplMethod = declaration.functionReferenceImplMethod
?: error("functionReferenceImplMethod is not set for ${declaration.render()}")
val singleStatement = (functionReferenceImplMethod.body as? IrBlockBody)?.statements?.singleOrNull()
?: error("Expected a single statement for the body of ${functionReferenceImplMethod.render()}")
require(singleStatement is IrReturn) {
"Expected a return statement: ${singleStatement.render()}"
}
val delegatingCall = singleStatement.value as? IrFunctionAccessExpression
?: error("Expected IrFunctionAccessExpression: ${singleStatement.value.render()}")
declaration.name = fileLowerState.getFunctionReferenceImplUniqueName(delegatingCall.symbol.owner).synthesizedName
}
}
})
}
}

/**
* Transforms a function reference into a subclass of `kotlin.native.internal.KFunctionImpl` and `kotlin.FunctionN`,
* or `kotlin.native.internal.KSuspendFunctionImpl` and `kotlin.KSuspendFunctionN` (for suspend functions/lambdas),
Expand Down Expand Up @@ -256,17 +221,20 @@ internal class FunctionReferenceLowering(val generationState: NativeGenerationSt
startOffset = this@FunctionReferenceBuilder.startOffset
endOffset = this@FunctionReferenceBuilder.endOffset
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL
name = SpecialNames.NO_NAME_PROVIDED
val reflectionTarget = (functionReference.reflectionTarget ?: functionReference.symbol).owner
if (isLambda) {
name = SpecialNames.NO_NAME_PROVIDED
} else {
name = generationState.fileLowerState.getFunctionReferenceImplUniqueName("FUNCTION_REFERENCE_FOR$${reflectionTarget.name}$").synthesizedName
}
visibility = DescriptorVisibilities.LOCAL
}.apply {
hasSyntheticNameToBeHiddenInReflection = true
parent = this@FunctionReferenceBuilder.parent

// The function reference class only needs to be generic over type parameters coming from an enclosing scope.
copyTypeParameters(typeParametersFromEnclosingScope)
createParameterDeclarations()

// copy the generated name for IrClass, partially solves KT-47194
generationState.copyLocalClassName(functionReference, this)
}

/**
Expand Down Expand Up @@ -381,7 +349,7 @@ internal class FunctionReferenceLowering(val generationState: NativeGenerationSt
}
}
val originalSuperMethod = transformedSuperMethod.suspendFunction ?: transformedSuperMethod
functionReferenceClass.functionReferenceImplMethod = buildInvokeMethod(originalSuperMethod)
buildInvokeMethod(originalSuperMethod)

functionReferenceClass.superTypes += superTypes
if (!isLambda) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.lower.InventNamesForLocalClasses
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.irFlag
import org.jetbrains.kotlin.ir.util.isAnonymousObject
import org.jetbrains.kotlin.name.Name

internal var IrClass.hasSyntheticNameToBeHiddenInReflection by irFlag(followAttributeOwner = true)

// TODO: consider replacing '$' by another delimeter that can't be used in class name specified with backticks (``)
internal class NativeInventNamesForLocalClasses(val generationState: NativeGenerationState) : InventNamesForLocalClasses(
shouldIncludeVariableName = false
) {
internal class NativeInventNamesForLocalClasses(val generationState: NativeGenerationState) : InventNamesForLocalClasses() {
override fun computeTopLevelClassName(clazz: IrClass): String = clazz.name.asString()
override fun sanitizeNameIfNeeded(name: String) = name

Expand All @@ -24,6 +26,11 @@ internal class NativeInventNamesForLocalClasses(val generationState: NativeGener
}

override fun putLocalClassName(declaration: IrAttributeContainer, localClassName: String) {
generationState.putLocalClassName(declaration, localClassName)
if (declaration is IrClass) {
if (declaration.isAnonymousObject) {
declaration.hasSyntheticNameToBeHiddenInReflection = true
}
declaration.name = Name.identifier(localClassName)
}
}
}
Loading

0 comments on commit adb2912

Please sign in to comment.