Don't generate DUPX instructions for in-range-literal expressions
Store argument into a local variable instead.
This commit is contained in:
+1
-1
@@ -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)
|
||||||
}
|
}
|
||||||
+3
-1
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
+79
-70
@@ -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,84 +50,95 @@ 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
|
||||||
|
|
||||||
val exitLabel1 = Label()
|
frameMap.useTmpVar(operandType) { arg1Var ->
|
||||||
val exitLabel2 = Label()
|
val exitLabel1 = 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)
|
||||||
// if (low bound is NOT satisfied) goto exitLabel1
|
v.store(arg1Var, operandType)
|
||||||
if (boundedValue.isLowInclusive) {
|
v.load(arg1Var, operandType)
|
||||||
// arg < low
|
|
||||||
v.swap()
|
// On stack: high low arg
|
||||||
comparisonGenerator.jumpIfLess(v, exitLabel1)
|
// if (low bound is NOT satisfied) goto exitLabel1
|
||||||
}
|
if (boundedValue.isLowInclusive) {
|
||||||
else {
|
// arg < low
|
||||||
// arg <= low
|
v.swap()
|
||||||
v.swap()
|
comparisonGenerator.jumpIfLess(v, exitLabel1)
|
||||||
comparisonGenerator.jumpIfLessOrEqual(v, exitLabel1)
|
}
|
||||||
|
else {
|
||||||
|
// arg <= low
|
||||||
|
v.swap()
|
||||||
|
comparisonGenerator.jumpIfLessOrEqual(v, exitLabel1)
|
||||||
|
}
|
||||||
|
|
||||||
|
v.load(arg1Var, operandType)
|
||||||
|
// On stack: high arg
|
||||||
|
// if (high bound is satisfied) goto jumpLabel
|
||||||
|
if (boundedValue.isHighInclusive) {
|
||||||
|
// arg <= high
|
||||||
|
v.swap()
|
||||||
|
comparisonGenerator.jumpIfLessOrEqual(v, jumpLabel)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// arg < high
|
||||||
|
v.swap()
|
||||||
|
comparisonGenerator.jumpIfLess(v, jumpLabel)
|
||||||
|
}
|
||||||
|
v.goTo(exitLabel2)
|
||||||
|
|
||||||
|
v.mark(exitLabel1)
|
||||||
|
AsmUtil.pop(v, operandType)
|
||||||
|
|
||||||
|
v.mark(exitLabel2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// On stack: high arg
|
|
||||||
// if (high bound is satisfied) goto jumpLabel
|
|
||||||
if (boundedValue.isHighInclusive) {
|
|
||||||
// arg <= high
|
|
||||||
v.swap()
|
|
||||||
comparisonGenerator.jumpIfLessOrEqual(v, jumpLabel)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// arg < high
|
|
||||||
v.swap()
|
|
||||||
comparisonGenerator.jumpIfLess(v, jumpLabel)
|
|
||||||
}
|
|
||||||
v.goTo(exitLabel2)
|
|
||||||
|
|
||||||
v.mark(exitLabel1)
|
|
||||||
AsmUtil.pop2(v, operandType)
|
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
val cmpHighLabel = Label()
|
frameMap.useTmpVar(operandType) { arg1Var ->
|
||||||
|
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)
|
||||||
// if ([low bound is satisfied]) goto cmpHighLabel
|
v.store(arg1Var, operandType)
|
||||||
if (boundedValue.isLowInclusive) {
|
v.load(arg1Var, operandType)
|
||||||
// arg >= low
|
|
||||||
v.swap()
|
|
||||||
comparisonGenerator.jumpIfGreaterOrEqual(v, cmpHighLabel)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// arg > low
|
|
||||||
v.swap()
|
|
||||||
comparisonGenerator.jumpIfGreater(v, cmpHighLabel)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Low bound is NOT satisfied, clear stack and goto jumpLabel
|
// On stack: high low arg
|
||||||
AsmUtil.pop2(v, operandType)
|
// if ([low bound is satisfied]) goto cmpHighLabel
|
||||||
v.goTo(jumpLabel)
|
if (boundedValue.isLowInclusive) {
|
||||||
|
// arg >= low
|
||||||
|
v.swap()
|
||||||
|
comparisonGenerator.jumpIfGreaterOrEqual(v, cmpHighLabel)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// arg > low
|
||||||
|
v.swap()
|
||||||
|
comparisonGenerator.jumpIfGreater(v, cmpHighLabel)
|
||||||
|
}
|
||||||
|
|
||||||
v.mark(cmpHighLabel)
|
// Low bound is NOT satisfied, clear stack and goto jumpLabel
|
||||||
// On stack: high arg
|
AsmUtil.pop(v, operandType)
|
||||||
// if ([high bound is NOT satisfied]) goto jumpLabel
|
v.goTo(jumpLabel)
|
||||||
if (boundedValue.isHighInclusive) {
|
|
||||||
// arg > high
|
v.mark(cmpHighLabel)
|
||||||
v.swap()
|
v.load(arg1Var, operandType)
|
||||||
comparisonGenerator.jumpIfGreater(v, jumpLabel)
|
// On stack: high arg
|
||||||
}
|
// if ([high bound is NOT satisfied]) goto jumpLabel
|
||||||
else {
|
if (boundedValue.isHighInclusive) {
|
||||||
// arg >= high
|
// arg > high
|
||||||
v.swap()
|
v.swap()
|
||||||
comparisonGenerator.jumpIfGreaterOrEqual(v, jumpLabel)
|
comparisonGenerator.jumpIfGreater(v, jumpLabel)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// arg >= high
|
||||||
|
v.swap()
|
||||||
|
comparisonGenerator.jumpIfGreaterOrEqual(v, jumpLabel)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+72
-64
@@ -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,78 +49,88 @@ 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 exitLabel2 = Label()
|
||||||
|
|
||||||
val exitLabel1 = Label()
|
boundedValue.putHighLow(v, operandType)
|
||||||
val exitLabel2 = Label()
|
|
||||||
|
|
||||||
boundedValue.putHighLow(v, operandType)
|
arg1.put(operandType, v)
|
||||||
arg1.put(operandType, v)
|
v.store(arg1Var, operandType)
|
||||||
AsmUtil.dupx(v, operandType)
|
v.load(arg1Var, operandType)
|
||||||
|
|
||||||
// On stack: high arg low arg
|
// 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
|
||||||
comparisonGenerator.jumpIfGreater(v, exitLabel1)
|
comparisonGenerator.jumpIfGreater(v, exitLabel1)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// low >= arg
|
||||||
|
comparisonGenerator.jumpIfGreaterOrEqual(v, exitLabel1)
|
||||||
|
}
|
||||||
|
|
||||||
|
v.load(arg1Var, operandType)
|
||||||
|
// On stack: high arg
|
||||||
|
// if (high bound is satisfied) goto jumpLabel
|
||||||
|
if (boundedValue.isHighInclusive) {
|
||||||
|
// high >= arg
|
||||||
|
comparisonGenerator.jumpIfGreaterOrEqual(v, jumpLabel)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// high > arg
|
||||||
|
comparisonGenerator.jumpIfGreater(v, jumpLabel)
|
||||||
|
}
|
||||||
|
v.goTo(exitLabel2)
|
||||||
|
|
||||||
|
v.mark(exitLabel1)
|
||||||
|
AsmUtil.pop(v, operandType)
|
||||||
|
|
||||||
|
v.mark(exitLabel2)
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// low >= arg
|
|
||||||
comparisonGenerator.jumpIfGreaterOrEqual(v, exitLabel1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// On stack: high arg
|
|
||||||
// if (high bound is satisfied) goto jumpLabel
|
|
||||||
if (boundedValue.isHighInclusive) {
|
|
||||||
// high >= arg
|
|
||||||
comparisonGenerator.jumpIfGreaterOrEqual(v, jumpLabel)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// high > arg
|
|
||||||
comparisonGenerator.jumpIfGreater(v, jumpLabel)
|
|
||||||
}
|
|
||||||
v.goTo(exitLabel2)
|
|
||||||
|
|
||||||
v.mark(exitLabel1)
|
|
||||||
AsmUtil.pop2(v, operandType)
|
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
val cmpHighLabel = Label()
|
frameMap.useTmpVar(operandType) { arg1Var ->
|
||||||
|
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)
|
||||||
// if ([low bound is satisfied]) goto cmpHighLabel
|
v.store(arg1Var, operandType)
|
||||||
if (boundedValue.isLowInclusive) {
|
v.load(arg1Var, operandType)
|
||||||
// low <= arg
|
|
||||||
comparisonGenerator.jumpIfLessOrEqual(v, cmpHighLabel)
|
// On stack: high low arg
|
||||||
}
|
// if ([low bound is satisfied]) goto cmpHighLabel
|
||||||
else {
|
if (boundedValue.isLowInclusive) {
|
||||||
// low < arg
|
// low <= arg
|
||||||
comparisonGenerator.jumpIfLess(v, cmpHighLabel)
|
comparisonGenerator.jumpIfLessOrEqual(v, cmpHighLabel)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// low < arg
|
||||||
|
comparisonGenerator.jumpIfLess(v, cmpHighLabel)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Low bound is NOT satisfied, clear stack and goto jumpLabel
|
||||||
|
AsmUtil.pop(v, operandType)
|
||||||
|
v.goTo(jumpLabel)
|
||||||
|
|
||||||
|
v.mark(cmpHighLabel)
|
||||||
|
v.load(arg1Var, operandType)
|
||||||
|
// On stack: high arg
|
||||||
|
// if ([high bound is NOT satisfied]) goto jumpLabel
|
||||||
|
if (boundedValue.isHighInclusive) {
|
||||||
|
// high < arg
|
||||||
|
comparisonGenerator.jumpIfLess(v, jumpLabel)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// high <= arg
|
||||||
|
comparisonGenerator.jumpIfLessOrEqual(v, jumpLabel)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Low bound is NOT satisfied, clear stack and goto jumpLabel
|
|
||||||
AsmUtil.pop2(v, operandType)
|
|
||||||
v.goTo(jumpLabel)
|
|
||||||
|
|
||||||
v.mark(cmpHighLabel)
|
|
||||||
// On stack: high arg
|
|
||||||
// if ([high bound is NOT satisfied]) goto jumpLabel
|
|
||||||
if (boundedValue.isHighInclusive) {
|
|
||||||
// high < arg
|
|
||||||
comparisonGenerator.jumpIfLess(v, jumpLabel)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// high <= arg
|
|
||||||
comparisonGenerator.jumpIfLessOrEqual(v, jumpLabel)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+12
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user