IR: using function descriptor valueParameters field instead of visiting children of IrCall

code
```
  fun foo(vararg x: Any?) {}
  fun bar() = foo()
```
produce following IR:
```
FUN public fun bar(): kotlin.Unit
      BLOCK_BODY
        RETURN type=kotlin.Nothing from='bar(): Unit'
          CALL 'foo(vararg Any?): Unit' type=kotlin.Unit origin=null
            x: BLOCK type=kotlin.Array<T> origin=null
              CALL 'constructor Array(Int)' type=kotlin.Array<T> origin=null
                <T>: Any?
                size: CONST Int type=kotlin.Int value='0'
```
This commit is contained in:
Vasily Levchenko
2017-02-01 16:43:02 +03:00
committed by vvlevchenko
parent bb43b6ab09
commit 2479593f44
@@ -47,17 +47,9 @@ class VarargInjectionLowering internal constructor(val context: Context): Functi
typeArguments = expression.descriptor.original.typeParameters.map { it to expression.getTypeArgument(it)!! }.toMap()) typeArguments = expression.descriptor.original.typeParameters.map { it to expression.getTypeArgument(it)!! }.toMap())
originalCall.dispatchReceiver = expression.dispatchReceiver originalCall.dispatchReceiver = expression.dispatchReceiver
originalCall.extensionReceiver = expression.extensionReceiver originalCall.extensionReceiver = expression.extensionReceiver
var parameterIndex = 0 functionDescriptor.valueParameters.forEach {
expression.acceptChildrenVoid(object:IrElementVisitorVoid{ originalCall.putValueArgument(it.index, if (varargToBlock.containsKey(it)) varargToBlock[it] else expression.getValueArgument(it))
override fun visitElement(element: IrElement) {
offset(expression, scope) {
val parameter = if (element is IrVararg && varargToBlock.containsKey(element))
varargToBlock[element]!!
else element
originalCall.putValueArgument(parameterIndex++, parameter as IrExpression)
} }
}
})
return originalCall return originalCall
} }
} }
@@ -65,41 +57,48 @@ class VarargInjectionLowering internal constructor(val context: Context): Functi
} }
private fun blockPerVararg(expression: IrCall, owner: FunctionDescriptor): Map<IrVararg, IrBlock> { private fun blockPerVararg(expression: IrCall, owner: FunctionDescriptor): Map<ValueParameterDescriptor, IrBlock> {
val varargArgs = mutableMapOf<IrVararg, IrBlock>() val varargArgs = mutableMapOf<ValueParameterDescriptor, IrBlock>()
val arrayConstructor = kArrayType.constructors.find { it.valueParameters.size == 1 } val arrayConstructor = kArrayType.constructors.find { it.valueParameters.size == 1 }!!
expression.acceptVoid(object : IrElementVisitorVoid {
val scope = owner.scope() val scope = owner.scope()
override fun visitElement(element: IrElement) { val calleeDescriptor = expression.descriptor
element.acceptChildrenVoid(this) calleeDescriptor.valueParameters
} .filter{ it.varargElementType != null && expression.getValueArgument(it) is IrVararg?}
.forEach {
override fun visitVararg(expression: IrVararg) { val type = it.varargElementType!!
val parameterExpression = expression.getValueArgument(it) as IrVararg?
offset(expression, scope) { offset(expression, scope) {
val hasSpreadElement = hasSpreadElement(expression) val hasSpreadElement = hasSpreadElement(parameterExpression)
val block = irBlock(kArrayType.defaultType) if (!hasSpreadElement && parameterExpression?.elements?.all { it is IrConst<*> && KotlinBuiltIns.isString(it.type)}?:false) {
if (!hasSpreadElement && expression.elements.all { it is IrConst<*> && KotlinBuiltIns.isString(it.type)}) {
log("skipped vararg expression because it's string array literal") log("skipped vararg expression because it's string array literal")
return return@forEach
}
val block = irBlock(kArrayType.defaultType)
val arrayConstructorCall = irCall(
descriptor = arrayConstructor,
typeArguments = mapOf(arrayConstructor.typeParameters[0] to type))
if (parameterExpression == null) {
arrayConstructorCall.putValueArgument(0, kIntZero)
block.statements.add(arrayConstructorCall)
varargArgs.put(it, block)
return@forEach
} }
val vars = expression.elements.map { val vars = parameterExpression.elements.map {
val initVar = scope.createTemporaryVariable((it as? IrSpreadElement)?.expression ?: it as IrExpression, "__elem\$", true) val initVar = scope.createTemporaryVariable((it as? IrSpreadElement)?.expression ?: it as IrExpression, "__elem\$", true)
block.statements.add(initVar) block.statements.add(initVar)
it to initVar it to initVar
}.toMap() }.toMap()
val arrayConstructorCall = irCall( arrayConstructorCall.putValueArgument(0, calculateArraySize(hasSpreadElement, scope, parameterExpression, vars))
descriptor = arrayConstructor!!,
typeArguments = mapOf(arrayConstructor.typeParameters[0] to expression.varargElementType))
arrayConstructorCall.putValueArgument(0, calculateArraySize(hasSpreadElement, scope, expression, vars))
val arrayTmpVariable = scope.createTemporaryVariable(arrayConstructorCall, "__array\$", true) val arrayTmpVariable = scope.createTemporaryVariable(arrayConstructorCall, "__array\$", true)
val indexTmpVariable = scope.createTemporaryVariable(kIntZero, "__index\$", true) val indexTmpVariable = scope.createTemporaryVariable(kIntZero, "__index\$", true)
block.statements.add(arrayTmpVariable) block.statements.add(arrayTmpVariable)
if (hasSpreadElement) { if (hasSpreadElement) {
block.statements.add(indexTmpVariable) block.statements.add(indexTmpVariable)
} }
expression.elements.forEachIndexed { i, element -> parameterExpression.elements.forEachIndexed { i, element ->
offset(expression, scope) { offset(parameterExpression, scope) {
log("element:$i> ${ir2string(element)}") log("element:$i> ${ir2string(element)}")
val dst = vars[element]!! val dst = vars[element]!!
if (element !is IrSpreadElement) { if (element !is IrSpreadElement) {
@@ -133,10 +132,9 @@ class VarargInjectionLowering internal constructor(val context: Context): Functi
} }
block.statements.add(irGet(arrayTmpVariable.descriptor)) block.statements.add(irGet(arrayTmpVariable.descriptor))
varargArgs.put(expression, block) varargArgs.put(it, block)
} }
} }
})
return varargArgs return varargArgs
} }
@@ -176,7 +174,7 @@ class VarargInjectionLowering internal constructor(val context: Context): Functi
} }
private fun hasSpreadElement(expression: IrVararg) = expression.elements.any { it is IrSpreadElement } private fun hasSpreadElement(expression: IrVararg?) = expression?.elements?.any { it is IrSpreadElement }?:false
private fun log(msg:String) { private fun log(msg:String) {
context.log("VARARG-INJECTOR: $msg") context.log("VARARG-INJECTOR: $msg")