Don't introduce additional variables for simple array assignment.

This commit is contained in:
Dmitry Petrov
2016-08-25 09:09:10 +03:00
committed by Dmitry Petrov
parent abb106c885
commit 54e6bbd007
17 changed files with 61 additions and 54 deletions
@@ -25,10 +25,10 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.scopes.receivers.* import org.jetbrains.kotlin.resolve.scopes.receivers.*
fun StatementGenerator.generateReceiverOrNull(ktDefaultElement: KtElement, receiver: ReceiverValue?): IntermediateValue? = fun StatementGenerator.generateReceiverOrNull(ktDefaultElement: KtElement, receiver: ReceiverValue?): Value? =
receiver?.let { generateReceiver(ktDefaultElement, receiver) } receiver?.let { generateReceiver(ktDefaultElement, receiver) }
fun StatementGenerator.generateReceiver(ktDefaultElement: KtElement, receiver: ReceiverValue): IntermediateValue { fun StatementGenerator.generateReceiver(ktDefaultElement: KtElement, receiver: ReceiverValue): Value {
if (receiver is TransientReceiver) { if (receiver is TransientReceiver) {
return TransientReceiverValue(ktDefaultElement.text, receiver.type) return TransientReceiverValue(ktDefaultElement.text, receiver.type)
} }
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.psi2ir.intermediate.CallBuilder import org.jetbrains.kotlin.psi2ir.intermediate.CallBuilder
import org.jetbrains.kotlin.psi2ir.intermediate.getValueArgumentsInParameterOrder import org.jetbrains.kotlin.psi2ir.intermediate.getValueArgumentsInParameterOrder
import org.jetbrains.kotlin.psi2ir.intermediate.isValueArgumentReorderingRequired import org.jetbrains.kotlin.psi2ir.intermediate.isValueArgumentReorderingRequired
import org.jetbrains.kotlin.psi2ir.intermediate.IntermediateValue import org.jetbrains.kotlin.psi2ir.intermediate.Value
import org.jetbrains.kotlin.psi2ir.intermediate.createRematerializableOrTemporary import org.jetbrains.kotlin.psi2ir.intermediate.createRematerializableOrTemporary
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
@@ -121,7 +121,7 @@ class CallGenerator(
valueArgumentsToValueParameters[valueArgument] = valueParameter valueArgumentsToValueParameters[valueArgument] = valueParameter
} }
val irArgumentValues = HashMap<ValueParameterDescriptor, IntermediateValue>() val irArgumentValues = HashMap<ValueParameterDescriptor, Value>()
for (valueArgument in valueArgumentsInEvaluationOrder) { for (valueArgument in valueArgumentsInEvaluationOrder) {
val valueParameter = valueArgumentsToValueParameters[valueArgument]!! val valueParameter = valueArgumentsToValueParameters[valueArgument]!!
@@ -302,11 +302,7 @@ class OperatorExpressionGenerator(
val ktLeft = expression.left!! val ktLeft = expression.left!!
val irRhs = statementGenerator.generateExpression(expression.right!!) val irRhs = statementGenerator.generateExpression(expression.right!!)
val irAssignmentReceiver = generateAssignmentReceiver(ktLeft, IrOperator.EQ) val irAssignmentReceiver = generateAssignmentReceiver(ktLeft, IrOperator.EQ)
return irAssignmentReceiver.assign(irRhs)
return if (irAssignmentReceiver is IntermediateReference)
irAssignmentReceiver.store(irRhs)
else
irAssignmentReceiver.assign { irLValue -> irLValue.store(irRhs) }
} }
private fun generateAssignmentReceiver(ktLeft: KtExpression, irOperator: IrOperator): AssignmentReceiver { private fun generateAssignmentReceiver(ktLeft: KtExpression, irOperator: IrOperator): AssignmentReceiver {
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.psi2ir.deparenthesize import org.jetbrains.kotlin.psi2ir.deparenthesize
import org.jetbrains.kotlin.psi2ir.intermediate.IntermediateValue import org.jetbrains.kotlin.psi2ir.intermediate.Value
import org.jetbrains.kotlin.psi2ir.intermediate.createRematerializableOrTemporary import org.jetbrains.kotlin.psi2ir.intermediate.createRematerializableOrTemporary
import org.jetbrains.kotlin.psi2ir.intermediate.setExplicitReceiverValue import org.jetbrains.kotlin.psi2ir.intermediate.setExplicitReceiverValue
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
@@ -84,7 +84,7 @@ class StatementGenerator(
return irBlock return irBlock
} }
fun declareComponentVariablesInBlock(multiDeclaration: KtDestructuringDeclaration, irBlock: IrBlockImpl, containerValue: IntermediateValue) { fun declareComponentVariablesInBlock(multiDeclaration: KtDestructuringDeclaration, irBlock: IrBlockImpl, containerValue: Value) {
val callGenerator = CallGenerator(this) val callGenerator = CallGenerator(this)
for ((index, ktEntry) in multiDeclaration.entries.withIndex()) { for ((index, ktEntry) in multiDeclaration.entries.withIndex()) {
val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry) val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry)
@@ -35,7 +35,7 @@ class ArrayAccessAssignmentReceiver(
indexedSetCall?.let { it.descriptor.valueParameters.last().type } ?: indexedSetCall?.let { it.descriptor.valueParameters.last().type } ?:
throw AssertionError("Array access should have either indexed-get call or indexed-set call") throw AssertionError("Array access should have either indexed-get call or indexed-set call")
override fun assign(withLValue: (IntermediateReference) -> IrExpression): IrExpression { override fun assign(withLValue: (LValue) -> IrExpression): IrExpression {
val hasResult = operator.isAssignmentOperatorWithResult() val hasResult = operator.isAssignmentOperatorWithResult()
val resultType = if (hasResult) type else callGenerator.context.builtIns.unitType val resultType = if (hasResult) type else callGenerator.context.builtIns.unitType
val irBlock = IrBlockImpl(startOffset, endOffset, resultType, hasResult, operator) val irBlock = IrBlockImpl(startOffset, endOffset, resultType, hasResult, operator)
@@ -54,7 +54,17 @@ class ArrayAccessAssignmentReceiver(
return irBlock return irBlock
} }
private fun CallBuilder.fillArrayAndIndexArguments(arrayValue: IntermediateValue, indexValues: List<IntermediateValue>) { override fun assign(value: IrExpression): IrExpression {
if (indexedSetCall == null) throw AssertionError("Array access without indexed-get call")
indexedSetCall.setExplicitReceiverValue(OnceExpressionValue(irArray))
irIndices.forEachIndexed { i, irIndex ->
indexedSetCall.irValueArgumentsByIndex[i] = irIndex
}
indexedSetCall.lastArgument = value
return callGenerator.generateCall(startOffset, endOffset, indexedSetCall, IrOperator.EQ)
}
private fun CallBuilder.fillArrayAndIndexArguments(arrayValue: Value, indexValues: List<Value>) {
setExplicitReceiverValue(arrayValue) setExplicitReceiverValue(arrayValue)
indexValues.forEachIndexed { i, irIndexValue -> indexValues.forEachIndexed { i, irIndexValue ->
irValueArgumentsByIndex[i] = irIndexValue.load() irValueArgumentsByIndex[i] = irIndexValue.load()
@@ -41,6 +41,12 @@ class CallBuilder(val original: ResolvedCall<*>) {
val CallBuilder.argumentsCount: Int get() = val CallBuilder.argumentsCount: Int get() =
irValueArgumentsByIndex.size irValueArgumentsByIndex.size
var CallBuilder.lastArgument: IrExpression?
get() = irValueArgumentsByIndex.last()
set(value) {
irValueArgumentsByIndex[argumentsCount - 1] = value
}
fun CallBuilder.getValueArgumentsInParameterOrder(): List<IrExpression?> = fun CallBuilder.getValueArgumentsInParameterOrder(): List<IrExpression?> =
descriptor.valueParameters.map { irValueArgumentsByIndex[it.index] } descriptor.valueParameters.map { irValueArgumentsByIndex[it.index] }
@@ -65,10 +71,10 @@ val CallBuilder.explicitReceiverParameter: ReceiverParameterDescriptor? get() =
val CallBuilder.explicitReceiverType: KotlinType? get() = val CallBuilder.explicitReceiverType: KotlinType? get() =
explicitReceiverParameter?.type explicitReceiverParameter?.type
fun CallBuilder.setExplicitReceiverValue(explicitReceiverValue: IntermediateValue) { fun CallBuilder.setExplicitReceiverValue(explicitReceiverValue: Value) {
val previousCallReceiver = callReceiver val previousCallReceiver = callReceiver
callReceiver = object : CallReceiver { callReceiver = object : CallReceiver {
override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression { override fun call(withDispatchAndExtensionReceivers: (Value?, Value?) -> IrExpression): IrExpression {
return previousCallReceiver.call { dispatchReceiverValue, extensionReceiverValue -> return previousCallReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
val newDispatchReceiverValue = if (hasExtensionReceiver) dispatchReceiverValue else explicitReceiverValue val newDispatchReceiverValue = if (hasExtensionReceiver) dispatchReceiverValue else explicitReceiverValue
val newExtensionReceiverValue = if (hasExtensionReceiver) explicitReceiverValue else null val newExtensionReceiverValue = if (hasExtensionReceiver) explicitReceiverValue else null
@@ -31,7 +31,7 @@ class LValueWithGetterAndSetterCalls(
val startOffset: Int, val startOffset: Int,
val endOffset: Int, val endOffset: Int,
val operator: IrOperator? = null val operator: IrOperator? = null
) : IntermediateReference { ) : LValue {
private val descriptor: CallableDescriptor = private val descriptor: CallableDescriptor =
getterCall?.descriptor ?: setterCall?.descriptor ?: getterCall?.descriptor ?: setterCall?.descriptor ?:
throw AssertionError("Call-based LValue should have either a getter or a setter call") throw AssertionError("Call-based LValue should have either a getter or a setter call")
@@ -29,7 +29,7 @@ class OnceCallValue(
val startOffset: Int, val startOffset: Int,
val endOffset: Int, val endOffset: Int,
val operator: IrOperator? = null val operator: IrOperator? = null
): IntermediateValue { ): Value {
private var instantiated = false private var instantiated = false
override fun load(): IrExpression { override fun load(): IrExpression {
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.psi2ir.generators.CallGenerator import org.jetbrains.kotlin.psi2ir.generators.CallGenerator
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
class OnceExpressionValue(val irExpression: IrExpression) : IntermediateValue { class OnceExpressionValue(val irExpression: IrExpression) : Value {
init { init {
irExpression.assertDetached() irExpression.assertDetached()
} }
@@ -21,14 +21,14 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.psi2ir.generators.Scope import org.jetbrains.kotlin.psi2ir.generators.Scope
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
class RematerializableValue(val irExpression: IrExpressionWithCopy) : IntermediateValue { class RematerializableValue(val irExpression: IrExpressionWithCopy) : Value {
override val type: KotlinType? override val type: KotlinType?
get() = irExpression.type get() = irExpression.type
override fun load(): IrExpression = irExpression.copy() override fun load(): IrExpression = irExpression.copy()
} }
fun createRematerializableValue(irExpression: IrExpression): IntermediateValue? = fun createRematerializableValue(irExpression: IrExpression): Value? =
(irExpression as? IrExpressionWithCopy)?.let { RematerializableValue(it) } (irExpression as? IrExpressionWithCopy)?.let { RematerializableValue(it) }
inline fun createRematerializableOrTemporary( inline fun createRematerializableOrTemporary(
@@ -36,7 +36,7 @@ inline fun createRematerializableOrTemporary(
irExpression: IrExpression, irExpression: IrExpression,
nameHint: String? = null, nameHint: String? = null,
addVariable: (IrVariable) -> Unit addVariable: (IrVariable) -> Unit
): IntermediateValue { ): Value {
val rematerializable = createRematerializableValue(irExpression) val rematerializable = createRematerializableValue(irExpression)
if (rematerializable != null) { if (rematerializable != null) {
return rematerializable return rematerializable
@@ -47,7 +47,7 @@ inline fun createRematerializableOrTemporary(
return VariableLValue(temporaryVariable) return VariableLValue(temporaryVariable)
} }
fun createRematerializableOrTemporary(scope: Scope, irExpression: IrExpression, block: IrBlockImpl, nameHint: String? = null): IntermediateValue = fun createRematerializableOrTemporary(scope: Scope, irExpression: IrExpression, block: IrBlockImpl, nameHint: String? = null): Value =
createRematerializableOrTemporary(scope, irExpression, nameHint) { createRematerializableOrTemporary(scope, irExpression, nameHint) {
block.addStatement(it) block.addStatement(it)
} }
@@ -31,14 +31,14 @@ class SafeCallReceiver(
val startOffset: Int, val startOffset: Int,
val endOffset: Int, val endOffset: Int,
val explicitReceiver: IrExpression, val explicitReceiver: IrExpression,
val implicitDispatchReceiverValue: IntermediateValue? val implicitDispatchReceiverValue: Value?
) : CallReceiver { ) : CallReceiver {
override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression { override fun call(withDispatchAndExtensionReceivers: (Value?, Value?) -> IrExpression): IrExpression {
val irTmp = generator.scope.createTemporaryVariable(explicitReceiver, "safe_receiver") val irTmp = generator.scope.createTemporaryVariable(explicitReceiver, "safe_receiver")
val safeReceiverValue = VariableLValue(irTmp) val safeReceiverValue = VariableLValue(irTmp)
val dispatchReceiverValue: IntermediateValue val dispatchReceiverValue: Value
val extensionReceiverValue: IntermediateValue? val extensionReceiverValue: Value?
if (implicitDispatchReceiverValue != null) { if (implicitDispatchReceiverValue != null) {
dispatchReceiverValue = implicitDispatchReceiverValue dispatchReceiverValue = implicitDispatchReceiverValue
extensionReceiverValue = safeReceiverValue extensionReceiverValue = safeReceiverValue
@@ -19,10 +19,10 @@ package org.jetbrains.kotlin.psi2ir.intermediate
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
class SimpleCallReceiver( class SimpleCallReceiver(
val dispatchReceiverValue: IntermediateValue?, val dispatchReceiverValue: Value?,
val extensionReceiverValue: IntermediateValue? val extensionReceiverValue: Value?
) : CallReceiver { ) : CallReceiver {
override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression { override fun call(withDispatchAndExtensionReceivers: (Value?, Value?) -> IrExpression): IrExpression {
return withDispatchAndExtensionReceivers(dispatchReceiverValue, extensionReceiverValue) return withDispatchAndExtensionReceivers(dispatchReceiverValue, extensionReceiverValue)
} }
} }
@@ -30,7 +30,7 @@ class SimplePropertyLValue(
val irOperator: IrOperator?, val irOperator: IrOperator?,
val descriptor: PropertyDescriptor, val descriptor: PropertyDescriptor,
val callReceiver: CallReceiver val callReceiver: CallReceiver
) : IntermediateReference, AssignmentReceiver { ) : LValue, AssignmentReceiver {
override val type: KotlinType? override val type: KotlinType?
get() = descriptor.type get() = descriptor.type
@@ -54,7 +54,7 @@ class SimplePropertyLValue(
} }
} }
override fun assign(withLValue: (IntermediateReference) -> IrExpression): IrExpression { override fun assign(withLValue: (LValue) -> IrExpression): IrExpression {
return callReceiver.call { dispatchReceiverValue, extensionReceiverValue -> return callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
val variablesForReceivers = SmartList<IrVariable>() val variablesForReceivers = SmartList<IrVariable>()
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.psi2ir.intermediate
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
class TransientReceiverValue(val description: String, override val type: KotlinType?): IntermediateValue { class TransientReceiverValue(val description: String, override val type: KotlinType?): Value {
override fun load(): IrExpression { override fun load(): IrExpression {
throw AssertionError("Transient receiver should not be instantiated: $description") throw AssertionError("Transient receiver should not be instantiated: $description")
} }
@@ -19,19 +19,20 @@ package org.jetbrains.kotlin.psi2ir.intermediate
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
interface IntermediateValue { interface Value {
fun load(): IrExpression fun load(): IrExpression
val type: KotlinType? val type: KotlinType?
} }
interface IntermediateReference : IntermediateValue { interface LValue : Value {
fun store(irExpression: IrExpression): IrExpression fun store(irExpression: IrExpression): IrExpression
} }
interface AssignmentReceiver { interface AssignmentReceiver {
fun assign(withLValue: (IntermediateReference) -> IrExpression): IrExpression fun assign(withLValue: (LValue) -> IrExpression): IrExpression
fun assign(value: IrExpression): IrExpression = assign { it.store(value) }
} }
interface CallReceiver { interface CallReceiver {
fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression fun call(withDispatchAndExtensionReceivers: (Value?, Value?) -> IrExpression): IrExpression
} }
@@ -29,7 +29,7 @@ class VariableLValue(
val endOffset: Int, val endOffset: Int,
val descriptor: VariableDescriptor, val descriptor: VariableDescriptor,
val irOperator: IrOperator? = null val irOperator: IrOperator? = null
) : IntermediateReference, AssignmentReceiver { ) : LValue, AssignmentReceiver {
constructor(irVariable: IrVariable, irOperator: IrOperator? = null) : constructor(irVariable: IrVariable, irOperator: IrOperator? = null) :
this(irVariable.startOffset, irVariable.endOffset, irVariable.descriptor, irOperator) this(irVariable.startOffset, irVariable.endOffset, irVariable.descriptor, irOperator)
@@ -41,6 +41,6 @@ class VariableLValue(
override fun store(irExpression: IrExpression): IrExpression = override fun store(irExpression: IrExpression): IrExpression =
IrSetVariableImpl(startOffset, endOffset, descriptor, irExpression, irOperator) IrSetVariableImpl(startOffset, endOffset, descriptor, irExpression, irOperator)
override fun assign(withLValue: (IntermediateReference) -> IrExpression): IrExpression = override fun assign(withLValue: (LValue) -> IrExpression): IrExpression =
withLValue(this) withLValue(this)
} }
+10 -16
View File
@@ -6,11 +6,10 @@ IrFile /arrayAssignment.kt
CALL .intArrayOf type=kotlin.IntArray operator=null CALL .intArrayOf type=kotlin.IntArray operator=null
elements: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.IntArray elements: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.IntArray
DUMMY vararg type=kotlin.Int DUMMY vararg type=kotlin.Int
BLOCK type=kotlin.Unit hasResult=false operator=EQ CALL .set type=kotlin.Unit operator=EQ
CALL .set type=kotlin.Unit operator=EQ $this: GET_VAR x type=kotlin.IntArray operator=null
$this: GET_VAR x type=kotlin.IntArray operator=null index: CONST Int type=kotlin.Int value='1'
index: CONST Int type=kotlin.Int value='1' value: CONST Int type=kotlin.Int value='0'
value: CONST Int type=kotlin.Int value='0'
IrFunction public fun foo(): kotlin.Int IrFunction public fun foo(): kotlin.Int
IrExpressionBody IrExpressionBody
BLOCK type=<no-type> hasResult=false operator=null BLOCK type=<no-type> hasResult=false operator=null
@@ -19,14 +18,9 @@ IrFile /arrayAssignment.kt
IrFunction public fun test2(): kotlin.Unit IrFunction public fun test2(): kotlin.Unit
IrExpressionBody IrExpressionBody
BLOCK type=<no-type> hasResult=false operator=null BLOCK type=<no-type> hasResult=false operator=null
BLOCK type=kotlin.Unit hasResult=false operator=EQ CALL .set type=kotlin.Unit operator=EQ
VAR val tmp0_array: kotlin.IntArray $this: CALL .intArrayOf type=kotlin.IntArray operator=null
CALL .intArrayOf type=kotlin.IntArray operator=null elements: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.IntArray
elements: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.IntArray DUMMY vararg type=kotlin.Int
DUMMY vararg type=kotlin.Int index: CALL .foo type=kotlin.Int operator=null
VAR val tmp1_index0: kotlin.Int value: CONST Int type=kotlin.Int value='1'
CALL .foo type=kotlin.Int operator=null
CALL .set type=kotlin.Unit operator=EQ
$this: GET_VAR tmp0_array type=kotlin.IntArray operator=null
index: GET_VAR tmp1_index0 type=kotlin.Int operator=null
value: CONST Int type=kotlin.Int value='1'