IR: refactor DefaultParameterInjector
This commit is contained in:
+53
-102
@@ -181,15 +181,9 @@ open class DefaultArgumentStubGenerator(
|
|||||||
private fun log(msg: () -> String) = context.log { "DEFAULT-REPLACER: ${msg()}" }
|
private fun log(msg: () -> String) = context.log { "DEFAULT-REPLACER: ${msg()}" }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun maskParameterDeclaration(function: IrFunction, number: Int) =
|
|
||||||
maskParameter(function, number)
|
|
||||||
|
|
||||||
private fun maskParameter(function: IrFunction, number: Int) =
|
private fun maskParameter(function: IrFunction, number: Int) =
|
||||||
function.valueParameters.single { it.name == parameterMaskName(number) }
|
function.valueParameters.single { it.name == parameterMaskName(number) }
|
||||||
|
|
||||||
private fun markerParameterDeclaration(function: IrFunction) =
|
|
||||||
function.valueParameters.single { it.name == kConstructorMarkerName }
|
|
||||||
|
|
||||||
val DEFAULT_DISPATCH_CALL = object : IrStatementOriginImpl("DEFAULT_DISPATCH_CALL") {}
|
val DEFAULT_DISPATCH_CALL = object : IrStatementOriginImpl("DEFAULT_DISPATCH_CALL") {}
|
||||||
|
|
||||||
open class DefaultParameterInjector(
|
open class DefaultParameterInjector(
|
||||||
@@ -206,29 +200,23 @@ open class DefaultParameterInjector(
|
|||||||
irBody.transformChildrenVoid(this)
|
irBody.transformChildrenVoid(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun visitFunctionAccessExpression(
|
private fun <T : IrFunctionAccessExpression> visitFunctionAccessExpression(expression: T, builder: (IrFunctionSymbol) -> T): T {
|
||||||
expression: IrFunctionAccessExpression,
|
|
||||||
builder: (IrFunctionSymbol) -> IrFunctionAccessExpression
|
|
||||||
): IrExpression {
|
|
||||||
val argumentsCount = (0 until expression.valueArgumentsCount).count { expression.getValueArgument(it) != null }
|
val argumentsCount = (0 until expression.valueArgumentsCount).count { expression.getValueArgument(it) != null }
|
||||||
if (argumentsCount == expression.symbol.owner.valueParameters.size)
|
if (argumentsCount == expression.symbol.owner.valueParameters.size)
|
||||||
return expression
|
return expression
|
||||||
|
|
||||||
val (symbol, params) = parametersForCall(expression) ?: return expression
|
val (symbol, params) = parametersForCall(expression) ?: return expression
|
||||||
val descriptor = symbol.descriptor
|
|
||||||
val declaration = symbol.owner
|
|
||||||
|
|
||||||
for (i in 0 until expression.typeArgumentsCount) {
|
for (i in 0 until expression.typeArgumentsCount) {
|
||||||
log { "$descriptor [$i]: $expression.getTypeArgument(i)" }
|
log { "${symbol.descriptor}[$i]: ${expression.getTypeArgument(i)}" }
|
||||||
}
|
}
|
||||||
declaration.typeParameters.forEach { log { "$declaration[${it.index}] : $it" } }
|
symbol.owner.typeParameters.forEach { log { "${symbol.owner}[${it.index}] : $it" } }
|
||||||
|
|
||||||
return builder(symbol).apply {
|
return builder(symbol).apply {
|
||||||
this.copyTypeArgumentsFrom(expression)
|
copyTypeArgumentsFrom(expression)
|
||||||
|
|
||||||
params.forEach {
|
params.forEachIndexed { i, value ->
|
||||||
log { "call::params@${it.first.index}/${it.first.name.asString()}: ${ir2string(it.second)}" }
|
log { "call::params@$i/${symbol.owner.valueParameters[i].name}: ${ir2string(value)}" }
|
||||||
putValueArgument(it.first.index, it.second)
|
putValueArgument(i, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchReceiver = expression.dispatchReceiver
|
dispatchReceiver = expression.dispatchReceiver
|
||||||
@@ -240,106 +228,73 @@ open class DefaultParameterInjector(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||||
super.visitDelegatingConstructorCall(expression)
|
expression.transformChildrenVoid()
|
||||||
|
|
||||||
return visitFunctionAccessExpression(expression) {
|
return visitFunctionAccessExpression(expression) {
|
||||||
IrDelegatingConstructorCallImpl(
|
with(expression) {
|
||||||
startOffset = expression.startOffset,
|
IrDelegatingConstructorCallImpl(startOffset, endOffset, type, it as IrConstructorSymbol, typeArgumentsCount)
|
||||||
endOffset = expression.endOffset,
|
}
|
||||||
type = context.irBuiltIns.unitType,
|
|
||||||
symbol = it as IrConstructorSymbol,
|
|
||||||
typeArgumentsCount = expression.typeArgumentsCount
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
|
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
|
||||||
super.visitConstructorCall(expression)
|
expression.transformChildrenVoid()
|
||||||
|
|
||||||
return visitFunctionAccessExpression(expression) {
|
return visitFunctionAccessExpression(expression) {
|
||||||
IrConstructorCallImpl.fromSymbolOwner(
|
with(expression) {
|
||||||
expression.startOffset,
|
IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, type, it as IrConstructorSymbol, DEFAULT_DISPATCH_CALL)
|
||||||
expression.endOffset,
|
}
|
||||||
expression.type,
|
|
||||||
it as IrConstructorSymbol,
|
|
||||||
it.owner.parentAsClass.typeParameters.size,
|
|
||||||
DEFAULT_DISPATCH_CALL
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall): IrExpression {
|
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall): IrExpression {
|
||||||
super.visitEnumConstructorCall(expression)
|
expression.transformChildrenVoid()
|
||||||
|
|
||||||
return visitFunctionAccessExpression(expression) {
|
return visitFunctionAccessExpression(expression) {
|
||||||
IrEnumConstructorCallImpl(
|
with(expression) {
|
||||||
expression.startOffset,
|
IrEnumConstructorCallImpl(startOffset, endOffset, type, it as IrConstructorSymbol)
|
||||||
expression.endOffset,
|
}
|
||||||
expression.type,
|
|
||||||
it as IrConstructorSymbol
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall): IrExpression {
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
super.visitCall(expression)
|
expression.transformChildrenVoid()
|
||||||
|
|
||||||
return visitFunctionAccessExpression(expression) {
|
return visitFunctionAccessExpression(expression) {
|
||||||
IrCallImpl(
|
with(expression) {
|
||||||
startOffset = expression.startOffset,
|
IrCallImpl(startOffset, endOffset, type, it, typeArgumentsCount, DEFAULT_DISPATCH_CALL, superQualifierSymbol)
|
||||||
endOffset = expression.endOffset,
|
}
|
||||||
type = expression.type,
|
|
||||||
symbol = it,
|
|
||||||
typeArgumentsCount = expression.typeArgumentsCount,
|
|
||||||
origin = DEFAULT_DISPATCH_CALL,
|
|
||||||
superQualifierSymbol = expression.superQualifierSymbol
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parametersForCall(
|
private fun parametersForCall(expression: IrFunctionAccessExpression): Pair<IrFunctionSymbol, List<IrExpression?>>? {
|
||||||
expression: IrFunctionAccessExpression
|
|
||||||
): Pair<IrFunctionSymbol, List<Pair<IrValueParameter, IrExpression?>>>? {
|
|
||||||
val declaration = expression.symbol.owner
|
|
||||||
val keyFunction = declaration.generateDefaultsFunction(context, skipInline, skipExternalMethods) ?: return null
|
|
||||||
val realFunction = if (keyFunction is IrSimpleFunction) keyFunction.resolveFakeOverride()!! else keyFunction
|
|
||||||
|
|
||||||
log { "$declaration -> $realFunction" }
|
|
||||||
val maskValues = Array((declaration.valueParameters.size + 31) / 32) { 0 }
|
|
||||||
val params = mutableListOf<Pair<IrValueParameter, IrExpression?>>()
|
|
||||||
params += declaration.valueParameters.mapIndexed { argIndex, _ ->
|
|
||||||
val valueArgument = expression.getValueArgument(argIndex)
|
|
||||||
if (valueArgument == null) {
|
|
||||||
val maskIndex = argIndex / 32
|
|
||||||
maskValues[maskIndex] = maskValues[maskIndex] or (1 shl (argIndex % 32))
|
|
||||||
}
|
|
||||||
val valueParameterDeclaration = realFunction.valueParameters[argIndex]
|
|
||||||
val defaultValueArgument = nullConst(expression.startOffset, expression.endOffset, valueParameterDeclaration)
|
|
||||||
valueParameterDeclaration to (valueArgument ?: defaultValueArgument)
|
|
||||||
}
|
|
||||||
|
|
||||||
val startOffset = expression.startOffset
|
val startOffset = expression.startOffset
|
||||||
val endOffset = expression.endOffset
|
val endOffset = expression.endOffset
|
||||||
maskValues.forEachIndexed { i, maskValue ->
|
val declaration = expression.symbol.owner
|
||||||
params += maskParameterDeclaration(realFunction, i) to IrConstImpl.int(
|
|
||||||
startOffset = startOffset,
|
val stubOverride = declaration.generateDefaultsFunction(context, skipInline, skipExternalMethods) ?: return null
|
||||||
endOffset = endOffset,
|
// We *have* to resolve the fake override here since on the JVM, a default stub for a function implemented
|
||||||
type = context.irBuiltIns.intType,
|
// in an interface does not leave an abstract method after being moved to DefaultImpls (see InterfaceLowering).
|
||||||
value = maskValue
|
// Calling the fake override on an implementation of that interface would then result in a call to a method
|
||||||
)
|
// that does not actually exist as DefaultImpls is not part of the inheritance hierarchy.
|
||||||
|
val stubFunction = if (stubOverride is IrSimpleFunction) stubOverride.resolveFakeOverride()!! else stubOverride
|
||||||
|
log { "$declaration -> $stubFunction" }
|
||||||
|
|
||||||
|
val realArgumentsNumber = declaration.valueParameters.size
|
||||||
|
val maskValues = IntArray((declaration.valueParameters.size + 31) / 32)
|
||||||
|
assert((stubFunction.valueParameters.size - realArgumentsNumber - maskValues.size) in listOf(0, 1)) {
|
||||||
|
"argument count mismatch: expected $realArgumentsNumber arguments + ${maskValues.size} masks + optional handler/marker, " +
|
||||||
|
"got ${stubFunction.valueParameters.size} total in ${stubFunction.render()}"
|
||||||
}
|
}
|
||||||
if (expression.symbol is IrConstructorSymbol) {
|
return stubFunction.symbol to stubFunction.valueParameters.mapIndexed { i, parameter ->
|
||||||
val defaultArgumentMarker = context.ir.symbols.defaultConstructorMarker
|
when {
|
||||||
params += markerParameterDeclaration(realFunction) to
|
i >= realArgumentsNumber + maskValues.size -> IrConstImpl.constNull(startOffset, endOffset, parameter.type)
|
||||||
IrConstImpl.constNull(startOffset, endOffset, defaultArgumentMarker.owner.defaultType.makeNullable())
|
i >= realArgumentsNumber -> IrConstImpl.int(startOffset, endOffset, parameter.type, maskValues[i - realArgumentsNumber])
|
||||||
} else if (context.ir.shouldGenerateHandlerParameterForDefaultBodyFun()) {
|
else -> {
|
||||||
params += realFunction.valueParameters.last() to
|
val valueArgument = expression.getValueArgument(i)
|
||||||
IrConstImpl.constNull(startOffset, endOffset, context.irBuiltIns.nothingNType)
|
if (valueArgument == null) {
|
||||||
|
maskValues[i / 32] = maskValues[i / 32] or (1 shl (i % 32))
|
||||||
|
}
|
||||||
|
valueArgument ?: nullConst(startOffset, endOffset, parameter)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
params.forEach {
|
|
||||||
log { "descriptor::${realFunction.name.asString()}#${it.first.index}: ${it.first.name.asString()}" }
|
|
||||||
}
|
|
||||||
return Pair(realFunction.symbol, params)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun nullConst(startOffset: Int, endOffset: Int, irParameter: IrValueParameter): IrExpression? =
|
protected open fun nullConst(startOffset: Int, endOffset: Int, irParameter: IrValueParameter): IrExpression? =
|
||||||
@@ -426,10 +381,8 @@ private fun IrFunction.generateDefaultsFunctionImpl(context: CommonBackendContex
|
|||||||
newFunction.addValueParameter(parameterMaskName(i).asString(), context.irBuiltIns.intType)
|
newFunction.addValueParameter(parameterMaskName(i).asString(), context.irBuiltIns.intType)
|
||||||
}
|
}
|
||||||
if (this is IrConstructor) {
|
if (this is IrConstructor) {
|
||||||
newFunction.addValueParameter(
|
val markerType = context.ir.symbols.defaultConstructorMarker.owner.defaultType.makeNullable()
|
||||||
kConstructorMarkerName.asString(),
|
newFunction.addValueParameter("marker".synthesizedString, markerType)
|
||||||
context.ir.symbols.defaultConstructorMarker.owner.defaultType.makeNullable()
|
|
||||||
)
|
|
||||||
} else if (context.ir.shouldGenerateHandlerParameterForDefaultBodyFun()) {
|
} else if (context.ir.shouldGenerateHandlerParameterForDefaultBodyFun()) {
|
||||||
newFunction.addValueParameter("handler".synthesizedString, context.irBuiltIns.anyNType)
|
newFunction.addValueParameter("handler".synthesizedString, context.irBuiltIns.anyNType)
|
||||||
}
|
}
|
||||||
@@ -439,6 +392,4 @@ private fun IrFunction.generateDefaultsFunctionImpl(context: CommonBackendContex
|
|||||||
newFunction
|
newFunction
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val kConstructorMarkerName = "marker".synthesizedName
|
|
||||||
|
|
||||||
private fun parameterMaskName(number: Int) = "mask$number".synthesizedName
|
private fun parameterMaskName(number: Int) = "mask$number".synthesizedName
|
||||||
|
|||||||
Reference in New Issue
Block a user