Rematerialize simple expressions (local variables, literals, $this, $receiver) when generating calls.

This commit is contained in:
Dmitry Petrov
2016-08-17 13:09:59 +03:00
committed by Dmitry Petrov
parent c1583c4368
commit 287d804131
10 changed files with 118 additions and 46 deletions
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.psi2ir.generators.values.IrTemporaryVariableValue
import org.jetbrains.kotlin.psi2ir.generators.values.IrValue
import org.jetbrains.kotlin.psi2ir.generators.values.createRematerializableValue
import org.jetbrains.kotlin.psi2ir.toExpectedType
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
import org.jetbrains.kotlin.resolve.calls.model.*
@@ -42,12 +43,30 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
private val receiverValues = HashMap<ReceiverValue, IrValue>()
private val valueArgumentValues = HashMap<ValueParameterDescriptor, IrValue>()
fun createTemporary(ktExpression: KtExpression, irExpression: IrExpression, nameHint: String? = null): IrVariable {
fun introduceTemporary(ktExpression: KtExpression, irExpression: IrExpression, nameHint: String? = null): IrVariable? {
val rematerializable = createRematerializableValue(irExpression)
if (rematerializable != null) {
putValue(ktExpression, rematerializable)
return null
}
val irTmpVar = temporaryVariableFactory.createTemporaryVariable(irExpression, nameHint)
putValue(ktExpression, IrTemporaryVariableValue(irTmpVar))
return irTmpVar
}
fun introduceTemporary(valueParameterDescriptor: ValueParameterDescriptor, irExpression: IrExpression): IrVariable? {
val rematerializable = createRematerializableValue(irExpression)
if (rematerializable != null) {
putValue(valueParameterDescriptor, rematerializable)
return null
}
val irTmpVar = temporaryVariableFactory.createTemporaryVariable(irExpression, valueParameterDescriptor.name.asString())
putValue(valueParameterDescriptor, IrTemporaryVariableValue(irTmpVar))
return irTmpVar
}
fun putValue(ktExpression: KtExpression, irValue: IrValue) {
expressionValues[ktExpression] = irValue
}
@@ -140,30 +159,30 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
// TODO use IrLetExpression?
val valueArgumentsInEvaluationOrder = resolvedCall.valueArguments.values
val valueParameters = resolvedCall.resultingDescriptor.valueParameters
val irBlock = IrBlockExpressionImpl(ktExpression.startOffset, ktExpression.endOffset, resultType,
hasResult = isUsedAsExpression(ktExpression),
isDesugared = true)
val valueArgumentsToValueParameters = HashMap<ResolvedValueArgument, ValueParameterDescriptor>()
for ((index, valueArgument) in resolvedCall.valueArgumentsByIndex!!.withIndex()) {
val valueParameter = resolvedCall.resultingDescriptor.valueParameters[index]
val valueParameter = valueParameters[index]
valueArgumentsToValueParameters[valueArgument] = valueParameter
}
val temporariesForValueArguments = HashMap<ResolvedValueArgument, Pair<VariableDescriptor, IrExpression>>()
for (valueArgument in valueArgumentsInEvaluationOrder) {
val valueParameter = valueArgumentsToValueParameters[valueArgument]!!
val irArgument = generateValueArgument(valueArgument, valueParameter) ?: continue
val irTemporary = temporaryVariableFactory.createTemporaryVariable(irArgument, valueParameter.name.asString())
temporariesForValueArguments[valueArgument] = Pair(irTemporary.descriptor, irArgument)
irBlock.addStatement(irTemporary)
val irTmpArg = introduceTemporary(valueParameter, irArgument)
irBlock.addIfNotNull(irTmpArg)
}
for ((index, valueArgument) in resolvedCall.valueArgumentsByIndex!!.withIndex()) {
val (temporaryDescriptor, irArgument) = temporariesForValueArguments[valueArgument]!!
val valueParameter = resolvedCall.resultingDescriptor.valueParameters[index]
val irGetTemporary = IrGetVariableExpressionImpl(irArgument.startOffset, irArgument.endOffset, temporaryDescriptor)
val valueParameter = valueParameters[index]
val irGetTemporary = valueArgumentValues[valueParameter]!!.load()
irCall.putArgument(index, irGetTemporary.toExpectedType(valueParameter.type))
}
@@ -28,15 +28,24 @@ import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi2ir.generators.values.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
import org.jetbrains.kotlin.types.expressions.OperatorConventions
val KT_OPERATOR_TO_IR_OPERATOR = hashMapOf(
KtTokens.PLUSEQ to IrOperator.PLUSEQ,
KtTokens.MINUSEQ to IrOperator.MINUSEQ,
KtTokens.MULTEQ to IrOperator.MULTEQ,
KtTokens.DIVEQ to IrOperator.DIVEQ,
KtTokens.PERCEQ to IrOperator.PERCEQ
KtTokens.PERCEQ to IrOperator.PERCEQ,
KtTokens.PLUS to IrOperator.PLUS,
KtTokens.MINUS to IrOperator.MINUS,
KtTokens.MUL to IrOperator.MUL,
KtTokens.DIV to IrOperator.DIV
)
val AUGMENTED_ASSIGNMENTS = KtTokens.AUGMENTED_ASSIGNMENTS
val BINARY_OPERATORS_WITH_CALLS = OperatorConventions.BINARY_OPERATION_NAMES.keys
class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerator): IrGenerator {
override val context: IrGeneratorContext get() = irStatementGenerator.context
@@ -45,7 +54,7 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
return when (ktOperator) {
KtTokens.EQ -> generateAssignment(expression)
in KtTokens.AUGMENTED_ASSIGNMENTS -> generateAugmentedAssignment(expression, ktOperator)
in AUGMENTED_ASSIGNMENTS -> generateAugmentedAssignment(expression, ktOperator)
else -> createDummyExpression(expression, ktOperator.toString())
}
}
@@ -16,10 +16,7 @@
package org.jetbrains.kotlin.psi2ir.generators.values
import org.jetbrains.kotlin.ir.expressions.IrBlockExpression
import org.jetbrains.kotlin.ir.expressions.IrBlockExpressionImpl
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrOperator
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset
@@ -98,11 +95,11 @@ class IrIndexedLValue(
}
private fun defineContextVariables(irBlock: IrBlockExpression, callGenerator: IrCallGenerator) {
irBlock.addStatement(callGenerator.createTemporary(ktArrayAccessExpression.arrayExpression!!, irArray, "array"))
irBlock.addIfNotNull(callGenerator.introduceTemporary(ktArrayAccessExpression.arrayExpression!!, irArray, "array"))
var index = 0
for ((ktIndexExpression, irIndexValue) in indexValues) {
irBlock.addStatement(callGenerator.createTemporary(ktIndexExpression, irIndexValue, "index${index++}"))
irBlock.addIfNotNull(callGenerator.introduceTemporary(ktIndexExpression, irIndexValue, "index${index++}"))
}
}
}
@@ -0,0 +1,51 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.psi2ir.generators.values
import org.jetbrains.kotlin.ir.expressions.*
interface IrRematerializableValue : IrValue
fun createRematerializableValue(irExpression: IrExpression): IrRematerializableValue? =
when (irExpression) {
is IrLiteralExpression<*> -> IrRematerializableLiteralValue(irExpression)
is IrGetVariableExpression -> IrRematerializableVariableValue(irExpression)
is IrGetExtensionReceiverExpression -> IrRematerializableExtensionReceiverValue(irExpression)
is IrThisExpression -> IrRematerializableThisValue(irExpression)
else -> null
}
class IrRematerializableLiteralValue(val irExpression: IrLiteralExpression<*>): IrRematerializableValue {
override fun load(): IrExpression =
IrLiteralExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.type,
irExpression.kind, irExpression.kind.valueOf(irExpression))
}
class IrRematerializableVariableValue(val irExpression: IrGetVariableExpression) : IrRematerializableValue {
override fun load(): IrExpression =
IrGetVariableExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.descriptor)
}
class IrRematerializableExtensionReceiverValue(val irExpression: IrGetExtensionReceiverExpression) : IrRematerializableValue {
override fun load(): IrExpression =
IrGetExtensionReceiverExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.type, irExpression.descriptor)
}
class IrRematerializableThisValue(val irExpression: IrThisExpression): IrRematerializableValue {
override fun load(): IrExpression =
IrThisExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.type, irExpression.classDescriptor)
}
@@ -33,6 +33,10 @@ interface IrBlockExpression : IrExpression {
fun addStatement(statement: IrStatement)
}
fun IrBlockExpression.addIfNotNull(statement: IrStatement?) {
if (statement != null) addStatement(statement)
}
class IrBlockExpressionImpl(
startOffset: Int,
endOffset: Int,
+2 -6
View File
@@ -5,11 +5,7 @@ IrFile /arrayAssignment.kt
VAR val x: kotlin.IntArray
CALL .intArrayOf type=kotlin.IntArray operator=
elements: DUMMY vararg type=kotlin.Int
VAR val tmp0_array: kotlin.IntArray
GET_VAR x type=kotlin.IntArray
VAR val tmp1_index0: kotlin.Int
LITERAL Int type=kotlin.Int value='1'
CALL .set type=kotlin.Unit operator=EQ
$this: GET_VAR tmp0_array type=kotlin.IntArray
index: GET_VAR tmp1_index0 type=kotlin.Int
$this: GET_VAR x type=kotlin.IntArray
index: LITERAL Int type=kotlin.Int value='1'
value: LITERAL Int type=kotlin.Int value='0'
+9 -15
View File
@@ -10,27 +10,21 @@ IrFile /arrayAugmentedAssignment1.kt
BLOCK type=<no-type> hasResult=false isDesugared=false
VAR var x: kotlin.IntArray
CALL .foo type=kotlin.IntArray operator=
VAR val tmp0_array: kotlin.IntArray
GET_VAR x type=kotlin.IntArray
VAR val tmp1_index0: kotlin.Int
LITERAL Int type=kotlin.Int value='0'
CALL .set type=kotlin.Unit operator=PLUSEQ
$this: GET_VAR tmp0_array type=kotlin.IntArray
index: GET_VAR tmp1_index0 type=kotlin.Int
$this: GET_VAR x type=kotlin.IntArray
index: LITERAL Int type=kotlin.Int value='0'
value: CALL .plus type=kotlin.Int operator=PLUSEQ
$this: CALL .get type=kotlin.Int operator=PLUSEQ
$this: GET_VAR tmp0_array type=kotlin.IntArray
index: GET_VAR tmp1_index0 type=kotlin.Int
$this: GET_VAR x type=kotlin.IntArray
index: LITERAL Int type=kotlin.Int value='0'
other: LITERAL Int type=kotlin.Int value='1'
VAR val tmp2_array: kotlin.IntArray
VAR val tmp0_array: kotlin.IntArray
CALL .foo type=kotlin.IntArray operator=
VAR val tmp3_index0: kotlin.Int
LITERAL Int type=kotlin.Int value='0'
CALL .set type=kotlin.Unit operator=MULTEQ
$this: GET_VAR tmp2_array type=kotlin.IntArray
index: GET_VAR tmp3_index0 type=kotlin.Int
$this: GET_VAR tmp0_array type=kotlin.IntArray
index: LITERAL Int type=kotlin.Int value='0'
value: CALL .times type=kotlin.Int operator=MULTEQ
$this: CALL .get type=kotlin.Int operator=MULTEQ
$this: GET_VAR tmp2_array type=kotlin.IntArray
index: GET_VAR tmp3_index0 type=kotlin.Int
$this: GET_VAR tmp0_array type=kotlin.IntArray
index: LITERAL Int type=kotlin.Int value='0'
other: LITERAL Int type=kotlin.Int value='2'
+4 -8
View File
@@ -4,16 +4,12 @@ IrFile /arrayAugmentedAssignment2.kt
IrFunction public fun IB.test(/*0*/ a: IA): kotlin.Unit
IrExpressionBody
BLOCK type=<no-type> hasResult=false isDesugared=false
VAR val tmp0_array: IA
GET_VAR a type=IA
VAR val tmp1_index0: kotlin.String
LITERAL String type=kotlin.String value=''
CALL .set type=kotlin.Unit operator=PLUSEQ
$this: $RECEIVER of: test type=IB
$receiver: GET_VAR tmp0_array type=IA
index: GET_VAR tmp1_index0 type=kotlin.String
$receiver: GET_VAR a type=IA
index: LITERAL String type=kotlin.String value=''
value: CALL .plus type=kotlin.Int operator=PLUSEQ
$this: CALL .get type=kotlin.Int operator=PLUSEQ
$this: GET_VAR tmp0_array type=IA
index: GET_VAR tmp1_index0 type=kotlin.String
$this: GET_VAR a type=IA
index: LITERAL String type=kotlin.String value=''
other: LITERAL Int type=kotlin.Int value='42'
@@ -9,4 +9,5 @@ fun reordered2() = 2
fun test() {
foo(a = noReorder1(), b = noReorder2())
foo(b = reordered1(), a = reordered2())
foo(b = 1, a = reordered2())
}
@@ -35,3 +35,8 @@ IrFile /callWithReorderedArguments.kt
CALL .foo type=kotlin.Unit operator=
a: GET_VAR tmp1_a type=kotlin.Int
b: GET_VAR tmp0_b type=kotlin.Int
VAR val tmp2_a: kotlin.Int
CALL .reordered2 type=kotlin.Int operator=
CALL .foo type=kotlin.Unit operator=
a: GET_VAR tmp2_a type=kotlin.Int
b: LITERAL Int type=kotlin.Int value='1'