Rematerialize simple expressions (local variables, literals, $this, $receiver) when generating calls.
This commit is contained in:
committed by
Dmitry Petrov
parent
c1583c4368
commit
287d804131
+28
-9
@@ -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))
|
||||
}
|
||||
|
||||
|
||||
+11
-2
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
+3
-6
@@ -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++}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
+51
@@ -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
@@ -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
@@ -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,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'
|
||||
|
||||
Reference in New Issue
Block a user