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,78 +57,84 @@ 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() val calleeDescriptor = expression.descriptor
override fun visitElement(element: IrElement) { calleeDescriptor.valueParameters
element.acceptChildrenVoid(this) .filter{ it.varargElementType != null && expression.getValueArgument(it) is IrVararg?}
} .forEach {
val type = it.varargElementType!!
val parameterExpression = expression.getValueArgument(it) as IrVararg?
offset(expression, scope) {
val hasSpreadElement = hasSpreadElement(parameterExpression)
if (!hasSpreadElement && parameterExpression?.elements?.all { it is IrConst<*> && KotlinBuiltIns.isString(it.type)}?:false) {
log("skipped vararg expression because it's string array literal")
return@forEach
}
val block = irBlock(kArrayType.defaultType)
val arrayConstructorCall = irCall(
descriptor = arrayConstructor,
typeArguments = mapOf(arrayConstructor.typeParameters[0] to type))
override fun visitVararg(expression: IrVararg) { if (parameterExpression == null) {
offset(expression, scope) { arrayConstructorCall.putValueArgument(0, kIntZero)
val hasSpreadElement = hasSpreadElement(expression) block.statements.add(arrayConstructorCall)
val block = irBlock(kArrayType.defaultType) varargArgs.put(it, block)
if (!hasSpreadElement && expression.elements.all { it is IrConst<*> && KotlinBuiltIns.isString(it.type)}) { return@forEach
log("skipped vararg expression because it's string array literal") }
return
}
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!!, val arrayTmpVariable = scope.createTemporaryVariable(arrayConstructorCall, "__array\$", true)
typeArguments = mapOf(arrayConstructor.typeParameters[0] to expression.varargElementType)) val indexTmpVariable = scope.createTemporaryVariable(kIntZero, "__index\$", true)
arrayConstructorCall.putValueArgument(0, calculateArraySize(hasSpreadElement, scope, expression, vars)) block.statements.add(arrayTmpVariable)
val arrayTmpVariable = scope.createTemporaryVariable(arrayConstructorCall, "__array\$", true) if (hasSpreadElement) {
val indexTmpVariable = scope.createTemporaryVariable(kIntZero, "__index\$", true) block.statements.add(indexTmpVariable)
block.statements.add(arrayTmpVariable) }
if (hasSpreadElement) { parameterExpression.elements.forEachIndexed { i, element ->
block.statements.add(indexTmpVariable) offset(parameterExpression, scope) {
} log("element:$i> ${ir2string(element)}")
expression.elements.forEachIndexed { i, element -> val dst = vars[element]!!
offset(expression, scope) { if (element !is IrSpreadElement) {
log("element:$i> ${ir2string(element)}") val setArrayElementCall = irCall(
val dst = vars[element]!! descriptor = kArraySetFunctionDescriptor,
if (element !is IrSpreadElement) { typeArguments = null
val setArrayElementCall = irCall( )
descriptor = kArraySetFunctionDescriptor, setArrayElementCall.dispatchReceiver = irGet(arrayTmpVariable.descriptor)
typeArguments = null setArrayElementCall.putValueArgument(0, if (hasSpreadElement) irGet(indexTmpVariable.descriptor) else irConstInt(i))
) setArrayElementCall.putValueArgument(1, irGet(dst.descriptor))
setArrayElementCall.dispatchReceiver = irGet(arrayTmpVariable.descriptor) block.statements.add(setArrayElementCall)
setArrayElementCall.putValueArgument(0, if (hasSpreadElement) irGet(indexTmpVariable.descriptor) else irConstInt(i)) if (hasSpreadElement) {
setArrayElementCall.putValueArgument(1, irGet(dst.descriptor)) block.statements.add(incrementVariable(indexTmpVariable.descriptor, kIntOne))
block.statements.add(setArrayElementCall)
if (hasSpreadElement) {
block.statements.add(incrementVariable(indexTmpVariable.descriptor, kIntOne))
}
} else {
val arraySizeVariable = scope.createTemporaryVariable(irArraySize(irGet(dst.descriptor)), "__length\$")
block.statements.add(arraySizeVariable)
val copyCall = irCall(kCopyRangeToDescriptor, null).apply {
extensionReceiver = irGet(dst.descriptor)
putValueArgument(0, irGet(arrayTmpVariable.descriptor)) /* destination */
putValueArgument(1, kIntZero) /* fromIndex */
putValueArgument(2, irGet(arraySizeVariable.descriptor)) /* toIndex */
putValueArgument(3, irGet(indexTmpVariable.descriptor)) /* destinationIndex */
}
block.statements.add(copyCall)
block.statements.add(incrementVariable(indexTmpVariable.descriptor,
irGet(arraySizeVariable.descriptor)))
log("element:$i:spread element> ${ir2string(element.expression)}")
} }
} else {
val arraySizeVariable = scope.createTemporaryVariable(irArraySize(irGet(dst.descriptor)), "__length\$")
block.statements.add(arraySizeVariable)
val copyCall = irCall(kCopyRangeToDescriptor, null).apply {
extensionReceiver = irGet(dst.descriptor)
putValueArgument(0, irGet(arrayTmpVariable.descriptor)) /* destination */
putValueArgument(1, kIntZero) /* fromIndex */
putValueArgument(2, irGet(arraySizeVariable.descriptor)) /* toIndex */
putValueArgument(3, irGet(indexTmpVariable.descriptor)) /* destinationIndex */
}
block.statements.add(copyCall)
block.statements.add(incrementVariable(indexTmpVariable.descriptor,
irGet(arraySizeVariable.descriptor)))
log("element:$i:spread element> ${ir2string(element.expression)}")
} }
} }
block.statements.add(irGet(arrayTmpVariable.descriptor))
varargArgs.put(expression, block)
} }
block.statements.add(irGet(arrayTmpVariable.descriptor))
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")