Don't generate DUPX instructions for in-range-literal expressions

Store argument into a local variable instead.
This commit is contained in:
Dmitry Petrov
2017-10-24 11:03:53 +03:00
parent 9b49e9139c
commit 354d54aef6
7 changed files with 170 additions and 146 deletions
@@ -41,5 +41,5 @@ class ComparableRangeLiteralRangeValue(
codegen: ExpressionCodegen, codegen: ExpressionCodegen,
operatorReference: KtSimpleNameExpression, operatorReference: KtSimpleNameExpression,
resolvedCall: ResolvedCall<out CallableDescriptor> resolvedCall: ResolvedCall<out CallableDescriptor>
) = InContinuousRangeOfComparableExpressionGenerator(operatorReference, boundedValue) ) = InContinuousRangeOfComparableExpressionGenerator(operatorReference, boundedValue, codegen.frameMap)
} }
@@ -42,7 +42,9 @@ abstract class PrimitiveNumberRangeIntrinsicRangeValue(rangeCall: ResolvedCall<o
): InExpressionGenerator { ): InExpressionGenerator {
val comparisonGenerator = getComparisonGeneratorForRangeContainsCall(codegen, resolvedCall) val comparisonGenerator = getComparisonGeneratorForRangeContainsCall(codegen, resolvedCall)
return if (comparisonGenerator != null) return if (comparisonGenerator != null)
InPrimitiveContinuousRangeExpressionGenerator(operatorReference, getBoundedValue(codegen), comparisonGenerator) InPrimitiveContinuousRangeExpressionGenerator(
operatorReference, getBoundedValue(codegen), comparisonGenerator, codegen.frameMap
)
else else
CallBasedInExpressionGenerator(codegen, operatorReference) CallBasedInExpressionGenerator(codegen, operatorReference)
} }
@@ -16,10 +16,7 @@
package org.jetbrains.kotlin.codegen.range.inExpression package org.jetbrains.kotlin.codegen.range.inExpression
import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.BranchedValue
import org.jetbrains.kotlin.codegen.Invert
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.range.BoundedValue import org.jetbrains.kotlin.codegen.range.BoundedValue
import org.jetbrains.kotlin.codegen.range.comparison.ObjectComparisonGenerator import org.jetbrains.kotlin.codegen.range.comparison.ObjectComparisonGenerator
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
@@ -30,7 +27,8 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
class InContinuousRangeOfComparableExpressionGenerator( class InContinuousRangeOfComparableExpressionGenerator(
operatorReference: KtSimpleNameExpression, operatorReference: KtSimpleNameExpression,
private val boundedValue: BoundedValue private val boundedValue: BoundedValue,
private val frameMap: FrameMap
) : InExpressionGenerator { ) : InExpressionGenerator {
private val isNotIn = operatorReference.getReferencedNameElementType() == KtTokens.NOT_IN private val isNotIn = operatorReference.getReferencedNameElementType() == KtTokens.NOT_IN
private val comparisonGenerator = ObjectComparisonGenerator private val comparisonGenerator = ObjectComparisonGenerator
@@ -52,14 +50,17 @@ class InContinuousRangeOfComparableExpressionGenerator(
private fun genJumpIfTrue(v: InstructionAdapter, jumpLabel: Label) { private fun genJumpIfTrue(v: InstructionAdapter, jumpLabel: Label) {
// if (arg is in range) goto jumpLabel // if (arg is in range) goto jumpLabel
frameMap.useTmpVar(operandType) { arg1Var ->
val exitLabel1 = Label() val exitLabel1 = Label()
val exitLabel2 = Label() val exitLabel2 = Label()
boundedValue.putHighLow(v, operandType) boundedValue.putHighLow(v, operandType)
arg1.put(operandType, v)
AsmUtil.dupx(v, operandType)
// On stack: high arg low arg arg1.put(operandType, v)
v.store(arg1Var, operandType)
v.load(arg1Var, operandType)
// On stack: high low arg
// if (low bound is NOT satisfied) goto exitLabel1 // if (low bound is NOT satisfied) goto exitLabel1
if (boundedValue.isLowInclusive) { if (boundedValue.isLowInclusive) {
// arg < low // arg < low
@@ -72,6 +73,7 @@ class InContinuousRangeOfComparableExpressionGenerator(
comparisonGenerator.jumpIfLessOrEqual(v, exitLabel1) comparisonGenerator.jumpIfLessOrEqual(v, exitLabel1)
} }
v.load(arg1Var, operandType)
// On stack: high arg // On stack: high arg
// if (high bound is satisfied) goto jumpLabel // if (high bound is satisfied) goto jumpLabel
if (boundedValue.isHighInclusive) { if (boundedValue.isHighInclusive) {
@@ -87,21 +89,26 @@ class InContinuousRangeOfComparableExpressionGenerator(
v.goTo(exitLabel2) v.goTo(exitLabel2)
v.mark(exitLabel1) v.mark(exitLabel1)
AsmUtil.pop2(v, operandType) AsmUtil.pop(v, operandType)
v.mark(exitLabel2) v.mark(exitLabel2)
} }
}
private fun genJumpIfFalse(v: InstructionAdapter, jumpLabel: Label) { private fun genJumpIfFalse(v: InstructionAdapter, jumpLabel: Label) {
// if (arg is NOT in range) goto jumpLabel // if (arg is NOT in range) goto jumpLabel
frameMap.useTmpVar(operandType) { arg1Var ->
val cmpHighLabel = Label() val cmpHighLabel = Label()
boundedValue.putHighLow(v, operandType) boundedValue.putHighLow(v, operandType)
arg1.put(operandType, v)
AsmUtil.dupx(v, operandType)
// On stack: high arg low arg arg1.put(operandType, v)
v.store(arg1Var, operandType)
v.load(arg1Var, operandType)
// On stack: high low arg
// if ([low bound is satisfied]) goto cmpHighLabel // if ([low bound is satisfied]) goto cmpHighLabel
if (boundedValue.isLowInclusive) { if (boundedValue.isLowInclusive) {
// arg >= low // arg >= low
@@ -115,10 +122,11 @@ class InContinuousRangeOfComparableExpressionGenerator(
} }
// Low bound is NOT satisfied, clear stack and goto jumpLabel // Low bound is NOT satisfied, clear stack and goto jumpLabel
AsmUtil.pop2(v, operandType) AsmUtil.pop(v, operandType)
v.goTo(jumpLabel) v.goTo(jumpLabel)
v.mark(cmpHighLabel) v.mark(cmpHighLabel)
v.load(arg1Var, operandType)
// On stack: high arg // On stack: high arg
// if ([high bound is NOT satisfied]) goto jumpLabel // if ([high bound is NOT satisfied]) goto jumpLabel
if (boundedValue.isHighInclusive) { if (boundedValue.isHighInclusive) {
@@ -134,3 +142,4 @@ class InContinuousRangeOfComparableExpressionGenerator(
} }
} }
} }
}
@@ -16,10 +16,7 @@
package org.jetbrains.kotlin.codegen.range.inExpression package org.jetbrains.kotlin.codegen.range.inExpression
import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.BranchedValue
import org.jetbrains.kotlin.codegen.Invert
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.range.BoundedValue import org.jetbrains.kotlin.codegen.range.BoundedValue
import org.jetbrains.kotlin.codegen.range.comparison.ComparisonGenerator import org.jetbrains.kotlin.codegen.range.comparison.ComparisonGenerator
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
@@ -31,7 +28,8 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
class InPrimitiveContinuousRangeExpressionGenerator( class InPrimitiveContinuousRangeExpressionGenerator(
operatorReference: KtSimpleNameExpression, operatorReference: KtSimpleNameExpression,
private val boundedValue: BoundedValue, private val boundedValue: BoundedValue,
private val comparisonGenerator: ComparisonGenerator private val comparisonGenerator: ComparisonGenerator,
private val frameMap: FrameMap
) : InExpressionGenerator { ) : InExpressionGenerator {
private val isNotIn = operatorReference.getReferencedNameElementType() == KtTokens.NOT_IN private val isNotIn = operatorReference.getReferencedNameElementType() == KtTokens.NOT_IN
@@ -51,15 +49,17 @@ class InPrimitiveContinuousRangeExpressionGenerator(
private fun genJumpIfTrue(v: InstructionAdapter, jumpLabel: Label) { private fun genJumpIfTrue(v: InstructionAdapter, jumpLabel: Label) {
// if (arg is in range) goto jumpLabel // if (arg is in range) goto jumpLabel
frameMap.useTmpVar(operandType) { arg1Var ->
val exitLabel1 = Label() val exitLabel1 = Label()
val exitLabel2 = Label() val exitLabel2 = Label()
boundedValue.putHighLow(v, operandType) boundedValue.putHighLow(v, operandType)
arg1.put(operandType, v)
AsmUtil.dupx(v, operandType)
// On stack: high arg low arg arg1.put(operandType, v)
v.store(arg1Var, operandType)
v.load(arg1Var, operandType)
// On stack: high low arg
// if (low bound is NOT satisfied) goto exitLabel1 // if (low bound is NOT satisfied) goto exitLabel1
if (boundedValue.isLowInclusive) { if (boundedValue.isLowInclusive) {
// low > arg // low > arg
@@ -70,6 +70,7 @@ class InPrimitiveContinuousRangeExpressionGenerator(
comparisonGenerator.jumpIfGreaterOrEqual(v, exitLabel1) comparisonGenerator.jumpIfGreaterOrEqual(v, exitLabel1)
} }
v.load(arg1Var, operandType)
// On stack: high arg // On stack: high arg
// if (high bound is satisfied) goto jumpLabel // if (high bound is satisfied) goto jumpLabel
if (boundedValue.isHighInclusive) { if (boundedValue.isHighInclusive) {
@@ -83,21 +84,25 @@ class InPrimitiveContinuousRangeExpressionGenerator(
v.goTo(exitLabel2) v.goTo(exitLabel2)
v.mark(exitLabel1) v.mark(exitLabel1)
AsmUtil.pop2(v, operandType) AsmUtil.pop(v, operandType)
v.mark(exitLabel2) v.mark(exitLabel2)
} }
}
private fun genJumpIfFalse(v: InstructionAdapter, jumpLabel: Label) { private fun genJumpIfFalse(v: InstructionAdapter, jumpLabel: Label) {
// if (arg is NOT in range) goto jumpLabel // if (arg is NOT in range) goto jumpLabel
frameMap.useTmpVar(operandType) { arg1Var ->
val cmpHighLabel = Label() val cmpHighLabel = Label()
boundedValue.putHighLow(v, operandType) boundedValue.putHighLow(v, operandType)
arg1.put(operandType, v)
AsmUtil.dupx(v, operandType)
// On stack: high arg low arg arg1.put(operandType, v)
v.store(arg1Var, operandType)
v.load(arg1Var, operandType)
// On stack: high low arg
// if ([low bound is satisfied]) goto cmpHighLabel // if ([low bound is satisfied]) goto cmpHighLabel
if (boundedValue.isLowInclusive) { if (boundedValue.isLowInclusive) {
// low <= arg // low <= arg
@@ -109,10 +114,11 @@ class InPrimitiveContinuousRangeExpressionGenerator(
} }
// Low bound is NOT satisfied, clear stack and goto jumpLabel // Low bound is NOT satisfied, clear stack and goto jumpLabel
AsmUtil.pop2(v, operandType) AsmUtil.pop(v, operandType)
v.goTo(jumpLabel) v.goTo(jumpLabel)
v.mark(cmpHighLabel) v.mark(cmpHighLabel)
v.load(arg1Var, operandType)
// On stack: high arg // On stack: high arg
// if ([high bound is NOT satisfied]) goto jumpLabel // if ([high bound is NOT satisfied]) goto jumpLabel
if (boundedValue.isHighInclusive) { if (boundedValue.isHighInclusive) {
@@ -124,5 +130,7 @@ class InPrimitiveContinuousRangeExpressionGenerator(
comparisonGenerator.jumpIfLessOrEqual(v, jumpLabel) comparisonGenerator.jumpIfLessOrEqual(v, jumpLabel)
} }
} }
}
} }
} }
@@ -0,0 +1,12 @@
// WITH_RUNTIME
fun test(a: Int) = a in 1 .. 10
fun test(a: Long) = a in 1L .. 10L
fun test(a: Float) = a in 1.0f .. 10.0f
fun test(a: Double) = a in 1.0 .. 10.0
fun test(a: String) = a in "abc" .. "def"
// 0 DUP_X1
// 0 DUP2_X1
// 0 DUP_X2
// 0 DUP2_X2
@@ -1,7 +0,0 @@
// WITH_RUNTIME
fun test(a: Long) = a in 1L .. 10L
// One DUP2_X2 generated for 'in' operator,
// no DUP2_X2 generated for range on stack.
// 1 DUP2_X2
@@ -2006,9 +2006,9 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("noSwap2ForConstLongRangeTo.kt") @TestMetadata("noDupXForLiteralRangeContains.kt")
public void testNoSwap2ForConstLongRangeTo() throws Exception { public void testNoDupXForLiteralRangeContains() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/ranges/noSwap2ForConstLongRangeTo.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/ranges/noDupXForLiteralRangeContains.kt");
doTest(fileName); doTest(fileName);
} }
} }