From 77cbd10f9cca99bd31d2a9c8db2bcfcf0f94b368 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 13 Feb 2019 14:16:54 +0300 Subject: [PATCH] psi2ir: don't generate temporaries in dynamic array augmented assignment In constructs such as 'd[i] += x', where both indexed get and indexed set are dynamic calls, it's safe to generate augmented assignment body directly, without temporary variables for array ('d') and index ('i'). Note that corresponding IntermediateValue's are OnceExpressionValue's, which would throw an exception if this assumption is violated. --- .../ArrayAccessAssignmentReceiver.kt | 45 ++++++++--- .../dynamicArrayAugmentedAssignment.txt | 75 +++++++------------ .../dynamicArrayIncrementDecrement.txt | 52 ++++--------- 3 files changed, 76 insertions(+), 96 deletions(-) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/ArrayAccessAssignmentReceiver.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/ArrayAccessAssignmentReceiver.kt index 6ddf96d6176..177779dcddf 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/ArrayAccessAssignmentReceiver.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/ArrayAccessAssignmentReceiver.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi2ir.generators.CallGenerator import org.jetbrains.kotlin.psi2ir.generators.pregenerateValueArgumentsUsing import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic import org.jetbrains.kotlin.types.KotlinType class ArrayAccessAssignmentReceiver( @@ -42,32 +43,59 @@ class ArrayAccessAssignmentReceiver( private val origin: IrStatementOrigin ) : AssignmentReceiver { + private val indexedGetDescriptor = indexedGetResolvedCall?.resultingDescriptor + private val indexedSetDescriptor = indexedSetResolvedCall?.resultingDescriptor + private val descriptor = - indexedGetResolvedCall?.resultingDescriptor - ?: indexedSetResolvedCall?.resultingDescriptor + indexedGetDescriptor + ?: indexedSetDescriptor ?: throw AssertionError("Array access should have either indexed-get call or indexed-set call") override fun assign(withLValue: (LValue) -> IrExpression): IrExpression { val kotlinType: KotlinType = - indexedGetResolvedCall?.run { resultingDescriptor.returnType!! } - ?: indexedSetResolvedCall?.run { resultingDescriptor.valueParameters.last().type } + indexedGetDescriptor?.returnType + ?: indexedSetDescriptor?.run { valueParameters.last().type } ?: throw AssertionError("Array access should have either indexed-get call or indexed-set call") val hasResult = origin.isAssignmentOperatorWithResult() val resultType = if (hasResult) kotlinType else callGenerator.context.builtIns.unitType val irResultType = callGenerator.translateType(resultType) + + if (indexedGetDescriptor?.isDynamic() != false && indexedSetDescriptor?.isDynamic() != false) { + return withLValue( + createLValue(kotlinType, OnceExpressionValue(irArray)) { _, irIndex -> + OnceExpressionValue(irIndex) + } + ) + } + val irBlock = IrBlockImpl(startOffset, endOffset, irResultType, origin) val irArrayValue = callGenerator.scope.createTemporaryVariableInBlock(callGenerator.context, irArray, irBlock, "array") - val ktExpressionToIrIndexValue = HashMap() + irBlock.inlineStatement( + withLValue( + createLValue(kotlinType, irArrayValue) { i, irIndex -> + callGenerator.scope.createTemporaryVariableInBlock(callGenerator.context, irIndex, irBlock, "index$i") + } + ) + ) + return irBlock + } + + private fun createLValue( + kotlinType: KotlinType, + irArrayValue: IntermediateValue, + createIndexValue: (Int, IrExpression) -> IntermediateValue + ): LValueWithGetterAndSetterCalls { + val ktExpressionToIrIndexValue = HashMap() for ((i, irIndex) in irIndexExpressions.withIndex()) { ktExpressionToIrIndexValue[ktIndexExpressions[i]] = - callGenerator.scope.createTemporaryVariableInBlock(callGenerator.context, irIndex, irBlock, "index$i") + createIndexValue(i, irIndex) } - val irLValue = LValueWithGetterAndSetterCalls( + return LValueWithGetterAndSetterCalls( callGenerator, descriptor, { indexedGetCall()?.fillArrayAndIndexArguments(irArrayValue, indexedGetResolvedCall!!, ktExpressionToIrIndexValue) }, @@ -75,9 +103,6 @@ class ArrayAccessAssignmentReceiver( callGenerator.translateType(kotlinType), startOffset, endOffset, origin ) - irBlock.inlineStatement(withLValue(irLValue)) - - return irBlock } override fun assign(value: IrExpression): IrExpression { diff --git a/compiler/testData/ir/irJsText/dynamic/dynamicArrayAugmentedAssignment.txt b/compiler/testData/ir/irJsText/dynamic/dynamicArrayAugmentedAssignment.txt index e07981b25b8..db041edefb5 100644 --- a/compiler/testData/ir/irJsText/dynamic/dynamicArrayAugmentedAssignment.txt +++ b/compiler/testData/ir/irJsText/dynamic/dynamicArrayAugmentedAssignment.txt @@ -2,53 +2,28 @@ FILE fqName: fileName:/dynamicArrayAugmentedAssignment.kt FUN name:testArrayAugmentedAssignment visibility:public modality:FINAL <> (d:dynamic) returnType:kotlin.Unit flags: VALUE_PARAMETER name:d index:0 type:dynamic flags: BLOCK_BODY - BLOCK type=kotlin.Unit origin=PLUSEQ - VAR IR_TEMPORARY_VARIABLE name:tmp0_array type:dynamic flags:val - GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null - VAR IR_TEMPORARY_VARIABLE name:tmp1_index0 type:kotlin.String flags:val - CONST String type=kotlin.String value="KEY" - DYN_OP operator=PLUSEQ type=kotlin.Unit - receiver: DYN_OP operator=ARRAY_ACCESS type=dynamic - receiver: GET_VAR 'tmp0_array: dynamic' type=dynamic origin=null - 0: GET_VAR 'tmp1_index0: String' type=kotlin.String origin=null - 0: CONST String type=kotlin.String value="+=" - BLOCK type=kotlin.Unit origin=MINUSEQ - VAR IR_TEMPORARY_VARIABLE name:tmp2_array type:dynamic flags:val - GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null - VAR IR_TEMPORARY_VARIABLE name:tmp3_index0 type:kotlin.String flags:val - CONST String type=kotlin.String value="KEY" - DYN_OP operator=MINUSEQ type=kotlin.Unit - receiver: DYN_OP operator=ARRAY_ACCESS type=dynamic - receiver: GET_VAR 'tmp2_array: dynamic' type=dynamic origin=null - 0: GET_VAR 'tmp3_index0: String' type=kotlin.String origin=null - 0: CONST String type=kotlin.String value="-=" - BLOCK type=kotlin.Unit origin=MULTEQ - VAR IR_TEMPORARY_VARIABLE name:tmp4_array type:dynamic flags:val - GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null - VAR IR_TEMPORARY_VARIABLE name:tmp5_index0 type:kotlin.String flags:val - CONST String type=kotlin.String value="KEY" - DYN_OP operator=MULEQ type=kotlin.Unit - receiver: DYN_OP operator=ARRAY_ACCESS type=dynamic - receiver: GET_VAR 'tmp4_array: dynamic' type=dynamic origin=null - 0: GET_VAR 'tmp5_index0: String' type=kotlin.String origin=null - 0: CONST String type=kotlin.String value="*=" - BLOCK type=kotlin.Unit origin=DIVEQ - VAR IR_TEMPORARY_VARIABLE name:tmp6_array type:dynamic flags:val - GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null - VAR IR_TEMPORARY_VARIABLE name:tmp7_index0 type:kotlin.String flags:val - CONST String type=kotlin.String value="KEY" - DYN_OP operator=DIVEQ type=kotlin.Unit - receiver: DYN_OP operator=ARRAY_ACCESS type=dynamic - receiver: GET_VAR 'tmp6_array: dynamic' type=dynamic origin=null - 0: GET_VAR 'tmp7_index0: String' type=kotlin.String origin=null - 0: CONST String type=kotlin.String value="/=" - BLOCK type=kotlin.Unit origin=PERCEQ - VAR IR_TEMPORARY_VARIABLE name:tmp8_array type:dynamic flags:val - GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null - VAR IR_TEMPORARY_VARIABLE name:tmp9_index0 type:kotlin.String flags:val - CONST String type=kotlin.String value="KEY" - DYN_OP operator=MODEQ type=kotlin.Unit - receiver: DYN_OP operator=ARRAY_ACCESS type=dynamic - receiver: GET_VAR 'tmp8_array: dynamic' type=dynamic origin=null - 0: GET_VAR 'tmp9_index0: String' type=kotlin.String origin=null - 0: CONST String type=kotlin.String value="%=" + DYN_OP operator=PLUSEQ type=kotlin.Unit + receiver: DYN_OP operator=ARRAY_ACCESS type=dynamic + receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null + 0: CONST String type=kotlin.String value="KEY" + 0: CONST String type=kotlin.String value="+=" + DYN_OP operator=MINUSEQ type=kotlin.Unit + receiver: DYN_OP operator=ARRAY_ACCESS type=dynamic + receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null + 0: CONST String type=kotlin.String value="KEY" + 0: CONST String type=kotlin.String value="-=" + DYN_OP operator=MULEQ type=kotlin.Unit + receiver: DYN_OP operator=ARRAY_ACCESS type=dynamic + receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null + 0: CONST String type=kotlin.String value="KEY" + 0: CONST String type=kotlin.String value="*=" + DYN_OP operator=DIVEQ type=kotlin.Unit + receiver: DYN_OP operator=ARRAY_ACCESS type=dynamic + receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null + 0: CONST String type=kotlin.String value="KEY" + 0: CONST String type=kotlin.String value="/=" + DYN_OP operator=MODEQ type=kotlin.Unit + receiver: DYN_OP operator=ARRAY_ACCESS type=dynamic + receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null + 0: CONST String type=kotlin.String value="KEY" + 0: CONST String type=kotlin.String value="%=" diff --git a/compiler/testData/ir/irJsText/dynamic/dynamicArrayIncrementDecrement.txt b/compiler/testData/ir/irJsText/dynamic/dynamicArrayIncrementDecrement.txt index 6d38fc7ee5e..61d97f409d1 100644 --- a/compiler/testData/ir/irJsText/dynamic/dynamicArrayIncrementDecrement.txt +++ b/compiler/testData/ir/irJsText/dynamic/dynamicArrayIncrementDecrement.txt @@ -3,42 +3,22 @@ FILE fqName: fileName:/dynamicArrayIncrementDecrement.kt VALUE_PARAMETER name:d index:0 type:dynamic flags: BLOCK_BODY VAR name:t1 type:dynamic flags:val - BLOCK type=dynamic origin=PREFIX_INCR - VAR IR_TEMPORARY_VARIABLE name:tmp0_array type:dynamic flags:val - GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null - VAR IR_TEMPORARY_VARIABLE name:tmp1_index0 type:kotlin.String flags:val - CONST String type=kotlin.String value="prefixIncr" - DYN_OP operator=PREFIX_INCREMENT type=dynamic - receiver: DYN_OP operator=ARRAY_ACCESS type=dynamic - receiver: GET_VAR 'tmp0_array: dynamic' type=dynamic origin=null - 0: GET_VAR 'tmp1_index0: String' type=kotlin.String origin=null + DYN_OP operator=PREFIX_INCREMENT type=dynamic + receiver: DYN_OP operator=ARRAY_ACCESS type=dynamic + receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null + 0: CONST String type=kotlin.String value="prefixIncr" VAR name:t2 type:dynamic flags:val - BLOCK type=dynamic origin=PREFIX_DECR - VAR IR_TEMPORARY_VARIABLE name:tmp2_array type:dynamic flags:val - GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null - VAR IR_TEMPORARY_VARIABLE name:tmp3_index0 type:kotlin.String flags:val - CONST String type=kotlin.String value="prefixDecr" - DYN_OP operator=PREFIX_DECREMENT type=dynamic - receiver: DYN_OP operator=ARRAY_ACCESS type=dynamic - receiver: GET_VAR 'tmp2_array: dynamic' type=dynamic origin=null - 0: GET_VAR 'tmp3_index0: String' type=kotlin.String origin=null + DYN_OP operator=PREFIX_DECREMENT type=dynamic + receiver: DYN_OP operator=ARRAY_ACCESS type=dynamic + receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null + 0: CONST String type=kotlin.String value="prefixDecr" VAR name:t3 type:dynamic flags:val - BLOCK type=dynamic origin=POSTFIX_INCR - VAR IR_TEMPORARY_VARIABLE name:tmp4_array type:dynamic flags:val - GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null - VAR IR_TEMPORARY_VARIABLE name:tmp5_index0 type:kotlin.String flags:val - CONST String type=kotlin.String value="postfixIncr" - DYN_OP operator=POSTFIX_INCREMENT type=dynamic - receiver: DYN_OP operator=ARRAY_ACCESS type=dynamic - receiver: GET_VAR 'tmp4_array: dynamic' type=dynamic origin=null - 0: GET_VAR 'tmp5_index0: String' type=kotlin.String origin=null + DYN_OP operator=POSTFIX_INCREMENT type=dynamic + receiver: DYN_OP operator=ARRAY_ACCESS type=dynamic + receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null + 0: CONST String type=kotlin.String value="postfixIncr" VAR name:t4 type:dynamic flags:val - BLOCK type=dynamic origin=POSTFIX_DECR - VAR IR_TEMPORARY_VARIABLE name:tmp6_array type:dynamic flags:val - GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null - VAR IR_TEMPORARY_VARIABLE name:tmp7_index0 type:kotlin.String flags:val - CONST String type=kotlin.String value="postfixDecr" - DYN_OP operator=POSTFIX_DECREMENT type=dynamic - receiver: DYN_OP operator=ARRAY_ACCESS type=dynamic - receiver: GET_VAR 'tmp6_array: dynamic' type=dynamic origin=null - 0: GET_VAR 'tmp7_index0: String' type=kotlin.String origin=null + DYN_OP operator=POSTFIX_DECREMENT type=dynamic + receiver: DYN_OP operator=ARRAY_ACCESS type=dynamic + receiver: GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null + 0: CONST String type=kotlin.String value="postfixDecr"