Implemented class delegation lowering

This commit is contained in:
Igor Chevdar
2017-02-21 17:17:53 +03:00
parent 0609cef5ac
commit dd350f88c8
5 changed files with 100 additions and 34 deletions
@@ -37,18 +37,19 @@ internal class SpecialDescriptorsFactory(val context: Context) {
false, false, false, false, false, false).initialize(outerClassDescriptor.defaultType, dispatchReceiverParameter = receiver)
}
fun getBridgeDescriptor(descriptor: OverriddenFunctionDescriptor): FunctionDescriptor {
val bridgeDirections = descriptor.bridgeDirections
assert(descriptor.needBridge,
{ "Function ${descriptor.descriptor} is not needed in a bridge to call overridden function ${descriptor.overriddenDescriptor}" })
return bridgesDescriptors.getOrPut(descriptor.descriptor to bridgeDirections) {
fun getBridgeDescriptor(overriddenFunctionDescriptor: OverriddenFunctionDescriptor): FunctionDescriptor {
val descriptor = overriddenFunctionDescriptor.descriptor.original
assert(overriddenFunctionDescriptor.needBridge,
{ "Function $descriptor is not needed in a bridge to call overridden function ${overriddenFunctionDescriptor.overriddenDescriptor}" })
val bridgeDirections = overriddenFunctionDescriptor.bridgeDirections
return bridgesDescriptors.getOrPut(descriptor to bridgeDirections) {
SimpleFunctionDescriptorImpl.create(
descriptor.descriptor.containingDeclaration,
descriptor.containingDeclaration,
Annotations.EMPTY,
("<bridge-" + bridgeDirections.toString() + ">" + descriptor.descriptor.functionName).synthesizedName,
("<bridge-" + bridgeDirections.toString() + ">" + descriptor.functionName).synthesizedName,
CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE).apply {
initializeBridgeDescriptor(this, descriptor.descriptor, bridgeDirections.array)
initializeBridgeDescriptor(this, descriptor, bridgeDirections.array)
}
}
}
@@ -55,8 +55,14 @@ internal class KonanLower(val context: Context) {
phaser.phase(KonanPhase.LOWER_VARARG) {
VarargInjectionLowering(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.LOWER_DELEGATION) {
DelegationLowering(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.BRIDGES_BUILDING) {
BridgesBuilding(context).lower(irFile)
BridgesBuilding(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.LOWER_DIRECT_BRIDGES_CALLS) {
DirectBridgesCallsLowering(context).runOnFilePostfix(irFile)
}
phaser.phase(KonanPhase.AUTOBOX) {
Autoboxing(context).lower(irFile)
@@ -25,6 +25,8 @@ enum class KonanPhase(val description: String,
/* ... ... */ LOWER_STRING_CONCAT("String concatenation lowering"),
/* ... ... */ LOWER_INITIALIZERS("Initializers lowering"),
/* ... ... */ BRIDGES_BUILDING("Bridges building"),
/* ... ... */ LOWER_DELEGATION("Delegation lowering"),
/* ... ... */ LOWER_DIRECT_BRIDGES_CALLS("Direct bridges calls lowering"),
/* ... */ BITCODE("LLVM BitCode Generation"),
/* ... ... */ RTTI("RTTI Generation"),
/* ... ... */ CODEGEN("Code Generation"),
@@ -16,22 +16,16 @@ internal class OverriddenFunctionDescriptor(val descriptor: FunctionDescriptor,
get() {
if (descriptor.modality == Modality.ABSTRACT) return false
return descriptor.kind == CallableMemberDescriptor.Kind.DELEGATION
//|| descriptor.needBridgeTo(overriddenDescriptor)
|| descriptor.target.needBridgeTo(overriddenDescriptor)
}
fun trivialOverride() = descriptor.original == overriddenDescriptor
val bridgeDirections: BridgeDirections
get() {
// if (descriptor.needBridgeTo(overriddenDescriptor))
// return descriptor.bridgeDirectionsTo(overriddenDescriptor)
return descriptor.target.bridgeDirectionsTo(overriddenDescriptor)
}
get() = descriptor.target.bridgeDirectionsTo(overriddenDescriptor)
val canBeCalledVirtually
val canBeCalledVirtually: Boolean
// We check that either method is open, or one of declarations it overrides is open.
get() = overriddenDescriptor.isOverridable || DescriptorUtils.getAllOverriddenDeclarations(overriddenDescriptor).any { it.isOverridable }
get() = overriddenDescriptor.isOverridable
|| DescriptorUtils.getAllOverriddenDeclarations(overriddenDescriptor).any { it.isOverridable }
override fun toString(): String {
@@ -76,9 +70,8 @@ internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val con
if (overridingMethod == null) {
superMethod
} else {
if (!superMethod.trivialOverride())
newVtableSlots.add(OverriddenFunctionDescriptor(overridingMethod, superMethod.descriptor))
// Overriding method is defined in the current class and is not inherited - take it as is.
// Add all possible (descriptor, overriddenDescriptor) edges for now, redundant will be removed later.
newVtableSlots.add(OverriddenFunctionDescriptor(overridingMethod, superMethod.descriptor))
newVtableSlots.add(OverriddenFunctionDescriptor(overridingMethod, overridingMethod))
OverriddenFunctionDescriptor(overridingMethod, superMethod.overriddenDescriptor)
}
@@ -94,15 +87,13 @@ internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val con
}
println()
// TODO: why put all pairs <descriptor, overriddenDescriptor>?
val zzz = inheritedVtableSlots.map { it.descriptor to it.bridgeDirections }.toSet()
methods// Find newly defined methods.
// TODO: Select target because method might be taken from default implementation of interface.
.mapTo(newVtableSlots) { OverriddenFunctionDescriptor(it, it) }
methods.mapTo(newVtableSlots) { OverriddenFunctionDescriptor(it, it) }
val filteredNewVtableSlots = newVtableSlots
.filter { (it.descriptor.kind.isReal || it.needBridge) && !zzz.contains(it.descriptor to it.bridgeDirections) }
.filter { !zzz.contains(it.descriptor to it.bridgeDirections) }
.distinctBy { it.descriptor to it.bridgeDirections }
.filter { it.descriptor.isOverridable }
println("VTABLE_ENTRIES new vtable:")
@@ -17,7 +17,6 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.KotlinType
internal class DirectBridgesCallsLowering(val context: Context) : BodyLoweringPass {
@@ -33,11 +32,14 @@ internal class DirectBridgesCallsLowering(val context: Context) : BodyLoweringPa
}
val target = descriptor.target
if (descriptor.kind != CallableMemberDescriptor.Kind.DELEGATION && !descriptor.original.needBridgeTo(target))
val needBridge = descriptor.original.needBridgeTo(target)
if (descriptor.kind != CallableMemberDescriptor.Kind.DELEGATION && !needBridge)
return expression
val toCall = if (needBridge) target else context.specialDescriptorsFactory.getBridgeDescriptor(OverriddenFunctionDescriptor(descriptor, target))
return IrCallImpl(expression.startOffset, expression.endOffset,
target, remapTypeArguments(expression, target)).apply {
toCall, remapTypeArguments(expression, toCall)).apply {
dispatchReceiver = expression.dispatchReceiver
extensionReceiver = expression.extensionReceiver
mapValueParameters { expression.getValueArgument(it)!! }
@@ -59,6 +61,73 @@ internal class DirectBridgesCallsLowering(val context: Context) : BodyLoweringPa
}
}
private object DECLARATION_ORIGIN_BRIDGE_METHOD :
IrDeclarationOriginImpl("BRIDGE_METHOD")
internal class DelegationLowering(val context: Context) : ClassLoweringPass {
override fun lower(irClass: IrClass) {
irClass.declarations.transformFlat {
when (it) {
is IrFunction -> {
val transformedFun = transformBridgeToDelegatedMethod(irClass, it)
if (transformedFun == null) null
else listOf(transformedFun)
}
is IrProperty -> {
val getter = transformBridgeToDelegatedMethod(irClass, it.getter)
val setter = transformBridgeToDelegatedMethod(irClass, it.setter)
if (getter != null || setter != null) {
it.getter = getter
it.setter = setter
}
null
}
else -> null
}
}
}
// TODO: hack because of broken IR for synthesized delegated members.
private fun transformBridgeToDelegatedMethod(irClass: IrClass, irFunction: IrFunction?): IrFunction? {
if (irFunction == null || irFunction.descriptor.kind != CallableMemberDescriptor.Kind.DELEGATION) return null
val body = irFunction.body as? IrBlockBody
?: throw AssertionError("Unexpected method body: ${irFunction.body}")
val statement = body.statements.single()
val delegatedCall = ((statement as? IrReturn)?.value ?: statement) as? IrCall
?: throw AssertionError("Unexpected method body: $statement")
val propertyGetter = delegatedCall.dispatchReceiver as? IrGetValue
?: throw AssertionError("Unexpected dispatch receiver: ${delegatedCall.dispatchReceiver}")
val propertyDescriptor = propertyGetter.descriptor as? PropertyDescriptor
?: throw AssertionError("Unexpected dispatch receiver descriptor: ${propertyGetter.descriptor}")
val delegated = context.specialDescriptorsFactory.getBridgeDescriptor(
OverriddenFunctionDescriptor(irFunction.descriptor, delegatedCall.descriptor as FunctionDescriptor))
val newFunction = IrFunctionImpl(irFunction.startOffset, irFunction.endOffset, DECLARATION_ORIGIN_BRIDGE_METHOD, delegated)
val irBlockBody = IrBlockBodyImpl(irFunction.startOffset, irFunction.endOffset)
val returnType = delegatedCall.descriptor.returnType!!
val irCall = IrCallImpl(irFunction.startOffset, irFunction.endOffset, returnType, delegatedCall.descriptor, null)
val receiver = IrGetValueImpl(irFunction.startOffset, irFunction.endOffset, irClass.descriptor.thisAsReceiverParameter)
irCall.dispatchReceiver = IrGetFieldImpl(irFunction.startOffset, irFunction.endOffset, propertyDescriptor, receiver)
irCall.extensionReceiver = delegated.extensionReceiverParameter?.let { extensionReceiver ->
IrGetValueImpl(irFunction.startOffset, irFunction.endOffset, extensionReceiver)
}
irCall.mapValueParameters { overriddenValueParameter ->
val delegatedValueParameter = delegated.valueParameters[overriddenValueParameter.index]
IrGetValueImpl(irFunction.startOffset, irFunction.endOffset, delegatedValueParameter)
}
if (KotlinBuiltIns.isUnit(returnType) || KotlinBuiltIns.isNothing(returnType)) {
irBlockBody.statements.add(irCall)
} else {
val irReturn = IrReturnImpl(irFunction.startOffset, irFunction.endOffset, context.builtIns.nothingType, delegated, irCall)
irBlockBody.statements.add(irReturn)
}
newFunction.body = irBlockBody
return newFunction
}
}
internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
override fun lower(irClass: IrClass) {
val functions = mutableSetOf<FunctionDescriptor?>()
@@ -78,7 +147,7 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
it?.let { function ->
function.allOverriddenDescriptors
.map { OverriddenFunctionDescriptor(function, it) }
.filter { it.needBridge }
.filter { !it.bridgeDirections.allNotNeeded() }
.filter { it.canBeCalledVirtually }
.distinctBy { it.bridgeDirections }
.forEach { buildBridge(it, irClass)
@@ -87,9 +156,6 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
}
}
private object DECLARATION_ORIGIN_BRIDGE_METHOD :
IrDeclarationOriginImpl("BRIDGE_METHOD")
private fun buildBridge(descriptor: OverriddenFunctionDescriptor, irClass: IrClass) {
println("BUILD_BRIDGE fun: ${descriptor.descriptor}")