JVM IR: collect potentialBridgeTargets in a list, then create bridges for all of them

This takes BridgeLowering time percentage from 1.3% to 1.0% of all
compiler time on a sample project, perhaps due to better data locality.
In addition, it simplifies stack traces by effectively merging all
bridge generation call sites into one, helping in future performance
investigations.
This commit is contained in:
Alexander Udalov
2020-08-12 20:08:25 +02:00
parent 9607414cf1
commit 35cace2540
@@ -161,15 +161,20 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
val isSynthetic: Boolean = false,
)
override fun lower(irFile: IrFile) = irFile.transformChildrenVoid()
private val potentialBridgeTargets = mutableListOf<IrSimpleFunction>()
override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid()
generateBridges()
potentialBridgeTargets.clear()
}
override fun visitClass(declaration: IrClass): IrStatement {
// Bridges in DefaultImpl classes are handled in InterfaceLowering.
if (declaration.origin == JvmLoweredDeclarationOrigin.DEFAULT_IMPLS || declaration.isAnnotationClass)
return super.visitClass(declaration)
// We generate bridges directly in the class, so we make a copy of the list of relevant members.
val potentialBridgeTargets = declaration.functions.filterTo(mutableListOf(), fun(irFunction: IrSimpleFunction): Boolean {
declaration.functions.filterTo(potentialBridgeTargets, fun(irFunction: IrSimpleFunction): Boolean {
// Only overrides may need bridges and so in particular, private and static functions do not.
// Note that this includes the static replacements for inline class functions (which are static, but have
// overriddenSymbols in order to produce correct signatures in the type mapper).
@@ -190,21 +195,25 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass
return !irFunction.isFakeOverride || irFunction.resolvesToClass()
})
return super.visitClass(declaration)
}
private fun generateBridges() {
for (member in potentialBridgeTargets) {
createBridges(declaration, member)
val parent = member.parentAsClass
createBridges(parent, member)
// For lambda classes, we move overrides from the `invoke` function to its bridge. This will allow us to avoid boxing
// the return type of `invoke` in codegen for lambdas with primitive return type. This does not apply to lambdas returning
// inline class types erasing to Any, which we need to box.
if (member.name == OperatorNameConventions.INVOKE
&& (declaration.origin == JvmLoweredDeclarationOrigin.LAMBDA_IMPL || declaration.origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL)
&& (parent.origin == JvmLoweredDeclarationOrigin.LAMBDA_IMPL ||
parent.origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL)
&& !member.returnType.isInlineClassErasingToAny
) {
member.overriddenSymbols = listOf()
member.overriddenSymbols = emptyList()
}
}
return super.visitClass(declaration)
}
private fun createBridges(irClass: IrClass, irFunction: IrSimpleFunction) {