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.scopes.receivers.*
fun StatementGenerator.generateReceiverOrNull(ktDefaultElement: KtElement, receiver: ReceiverValue?): IntermediateValue? =
fun StatementGenerator.generateReceiverOrNull(ktDefaultElement: KtElement, receiver: ReceiverValue?): Value? =
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) {
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.getValueArgumentsInParameterOrder
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.resolve.calls.model.ResolvedValueArgument
import org.jetbrains.kotlin.types.KotlinType
@@ -121,7 +121,7 @@ class CallGenerator(
valueArgumentsToValueParameters[valueArgument] = valueParameter
}
val irArgumentValues = HashMap<ValueParameterDescriptor, IntermediateValue>()
val irArgumentValues = HashMap<ValueParameterDescriptor, Value>()
for (valueArgument in valueArgumentsInEvaluationOrder) {
val valueParameter = valueArgumentsToValueParameters[valueArgument]!!
@@ -302,11 +302,7 @@ class OperatorExpressionGenerator(
val ktLeft = expression.left!!
val irRhs = statementGenerator.generateExpression(expression.right!!)
val irAssignmentReceiver = generateAssignmentReceiver(ktLeft, IrOperator.EQ)
return if (irAssignmentReceiver is IntermediateReference)
irAssignmentReceiver.store(irRhs)
else
irAssignmentReceiver.assign { irLValue -> irLValue.store(irRhs) }
return irAssignmentReceiver.assign(irRhs)
}
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.startOffset
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.setExplicitReceiverValue
import org.jetbrains.kotlin.resolve.BindingContext
@@ -84,7 +84,7 @@ class StatementGenerator(
return irBlock
}
fun declareComponentVariablesInBlock(multiDeclaration: KtDestructuringDeclaration, irBlock: IrBlockImpl, containerValue: IntermediateValue) {
fun declareComponentVariablesInBlock(multiDeclaration: KtDestructuringDeclaration, irBlock: IrBlockImpl, containerValue: Value) {
val callGenerator = CallGenerator(this)
for ((index, ktEntry) in multiDeclaration.entries.withIndex()) {
val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry)
@@ -35,7 +35,7 @@ class ArrayAccessAssignmentReceiver(
indexedSetCall?.let { it.descriptor.valueParameters.last().type } ?:
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 resultType = if (hasResult) type else callGenerator.context.builtIns.unitType
val irBlock = IrBlockImpl(startOffset, endOffset, resultType, hasResult, operator)
@@ -54,7 +54,17 @@ class ArrayAccessAssignmentReceiver(
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)
indexValues.forEachIndexed { i, irIndexValue ->
irValueArgumentsByIndex[i] = irIndexValue.load()
@@ -41,6 +41,12 @@ class CallBuilder(val original: ResolvedCall<*>) {
val CallBuilder.argumentsCount: Int get() =
irValueArgumentsByIndex.size
var CallBuilder.lastArgument: IrExpression?
get() = irValueArgumentsByIndex.last()
set(value) {
irValueArgumentsByIndex[argumentsCount - 1] = value
}
fun CallBuilder.getValueArgumentsInParameterOrder(): List<IrExpression?> =
descriptor.valueParameters.map { irValueArgumentsByIndex[it.index] }
@@ -65,10 +71,10 @@ val CallBuilder.explicitReceiverParameter: ReceiverParameterDescriptor? get() =
val CallBuilder.explicitReceiverType: KotlinType? get() =
explicitReceiverParameter?.type
fun CallBuilder.setExplicitReceiverValue(explicitReceiverValue: IntermediateValue) {
fun CallBuilder.setExplicitReceiverValue(explicitReceiverValue: Value) {
val previousCallReceiver = 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 ->
val newDispatchReceiverValue = if (hasExtensionReceiver) dispatchReceiverValue else explicitReceiverValue
val newExtensionReceiverValue = if (hasExtensionReceiver) explicitReceiverValue else null
@@ -31,7 +31,7 @@ class LValueWithGetterAndSetterCalls(
val startOffset: Int,
val endOffset: Int,
val operator: IrOperator? = null
) : IntermediateReference {
) : LValue {
private val descriptor: CallableDescriptor =
getterCall?.descriptor ?: setterCall?.descriptor ?:
throw AssertionError("Call-based LValue should have either a getter or a setter call")
@@ -29,7 +29,7 @@ class OnceCallValue(
val startOffset: Int,
val endOffset: Int,
val operator: IrOperator? = null
): IntermediateValue {
): Value {
private var instantiated = false
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.types.KotlinType
class OnceExpressionValue(val irExpression: IrExpression) : IntermediateValue {
class OnceExpressionValue(val irExpression: IrExpression) : Value {
init {
irExpression.assertDetached()
}
@@ -21,14 +21,14 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.psi2ir.generators.Scope
import org.jetbrains.kotlin.types.KotlinType
class RematerializableValue(val irExpression: IrExpressionWithCopy) : IntermediateValue {
class RematerializableValue(val irExpression: IrExpressionWithCopy) : Value {
override val type: KotlinType?
get() = irExpression.type
override fun load(): IrExpression = irExpression.copy()
}
fun createRematerializableValue(irExpression: IrExpression): IntermediateValue? =
fun createRematerializableValue(irExpression: IrExpression): Value? =
(irExpression as? IrExpressionWithCopy)?.let { RematerializableValue(it) }
inline fun createRematerializableOrTemporary(
@@ -36,7 +36,7 @@ inline fun createRematerializableOrTemporary(
irExpression: IrExpression,
nameHint: String? = null,
addVariable: (IrVariable) -> Unit
): IntermediateValue {
): Value {
val rematerializable = createRematerializableValue(irExpression)
if (rematerializable != null) {
return rematerializable
@@ -47,7 +47,7 @@ inline fun createRematerializableOrTemporary(
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) {
block.addStatement(it)
}
@@ -31,14 +31,14 @@ class SafeCallReceiver(
val startOffset: Int,
val endOffset: Int,
val explicitReceiver: IrExpression,
val implicitDispatchReceiverValue: IntermediateValue?
val implicitDispatchReceiverValue: Value?
) : 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 safeReceiverValue = VariableLValue(irTmp)
val dispatchReceiverValue: IntermediateValue
val extensionReceiverValue: IntermediateValue?
val dispatchReceiverValue: Value
val extensionReceiverValue: Value?
if (implicitDispatchReceiverValue != null) {
dispatchReceiverValue = implicitDispatchReceiverValue
extensionReceiverValue = safeReceiverValue
@@ -19,10 +19,10 @@ package org.jetbrains.kotlin.psi2ir.intermediate
import org.jetbrains.kotlin.ir.expressions.IrExpression
class SimpleCallReceiver(
val dispatchReceiverValue: IntermediateValue?,
val extensionReceiverValue: IntermediateValue?
val dispatchReceiverValue: Value?,
val extensionReceiverValue: Value?
) : CallReceiver {
override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression {
override fun call(withDispatchAndExtensionReceivers: (Value?, Value?) -> IrExpression): IrExpression {
return withDispatchAndExtensionReceivers(dispatchReceiverValue, extensionReceiverValue)
}
}
@@ -30,7 +30,7 @@ class SimplePropertyLValue(
val irOperator: IrOperator?,
val descriptor: PropertyDescriptor,
val callReceiver: CallReceiver
) : IntermediateReference, AssignmentReceiver {
) : LValue, AssignmentReceiver {
override val type: KotlinType?
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 ->
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.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 {
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.types.KotlinType
interface IntermediateValue {
interface Value {
fun load(): IrExpression
val type: KotlinType?
}
interface IntermediateReference : IntermediateValue {
interface LValue : Value {
fun store(irExpression: IrExpression): IrExpression
}
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 {
fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression
fun call(withDispatchAndExtensionReceivers: (Value?, Value?) -> IrExpression): IrExpression
}
@@ -29,7 +29,7 @@ class VariableLValue(
val endOffset: Int,
val descriptor: VariableDescriptor,
val irOperator: IrOperator? = null
) : IntermediateReference, AssignmentReceiver {
) : LValue, AssignmentReceiver {
constructor(irVariable: IrVariable, irOperator: IrOperator? = null) :
this(irVariable.startOffset, irVariable.endOffset, irVariable.descriptor, irOperator)
@@ -41,6 +41,6 @@ class VariableLValue(
override fun store(irExpression: IrExpression): IrExpression =
IrSetVariableImpl(startOffset, endOffset, descriptor, irExpression, irOperator)
override fun assign(withLValue: (IntermediateReference) -> IrExpression): IrExpression =
override fun assign(withLValue: (LValue) -> IrExpression): IrExpression =
withLValue(this)
}
+10 -16
View File
@@ -6,11 +6,10 @@ IrFile /arrayAssignment.kt
CALL .intArrayOf type=kotlin.IntArray operator=null
elements: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.IntArray
DUMMY vararg type=kotlin.Int
BLOCK type=kotlin.Unit hasResult=false operator=EQ
CALL .set type=kotlin.Unit operator=EQ
$this: GET_VAR x type=kotlin.IntArray operator=null
index: CONST Int type=kotlin.Int value='1'
value: CONST Int type=kotlin.Int value='0'
CALL .set type=kotlin.Unit operator=EQ
$this: GET_VAR x type=kotlin.IntArray operator=null
index: CONST Int type=kotlin.Int value='1'
value: CONST Int type=kotlin.Int value='0'
IrFunction public fun foo(): kotlin.Int
IrExpressionBody
BLOCK type=<no-type> hasResult=false operator=null
@@ -19,14 +18,9 @@ IrFile /arrayAssignment.kt
IrFunction public fun test2(): kotlin.Unit
IrExpressionBody
BLOCK type=<no-type> hasResult=false operator=null
BLOCK type=kotlin.Unit hasResult=false operator=EQ
VAR val tmp0_array: kotlin.IntArray
CALL .intArrayOf type=kotlin.IntArray operator=null
elements: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.IntArray
DUMMY vararg type=kotlin.Int
VAR val tmp1_index0: kotlin.Int
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'
CALL .set type=kotlin.Unit operator=EQ
$this: CALL .intArrayOf type=kotlin.IntArray operator=null
elements: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.IntArray
DUMMY vararg type=kotlin.Int
index: CALL .foo type=kotlin.Int operator=null
value: CONST Int type=kotlin.Int value='1'