diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java index 084a07f0576..1faa105b6ab 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java @@ -798,6 +798,16 @@ public class AsmUtil { } } + public static void pop2(@NotNull MethodVisitor v, @NotNull Type type) { + if (type.getSize() == 2) { + v.visitInsn(Opcodes.POP2); + v.visitInsn(Opcodes.POP2); + } + else { + v.visitInsn(Opcodes.POP2); + } + } + public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) { dup(v, type.getSize()); } @@ -814,6 +824,22 @@ public class AsmUtil { } } + public static void dupx(@NotNull InstructionAdapter v, @NotNull Type type) { + dupx(v, type.getSize()); + } + + private static void dupx(@NotNull InstructionAdapter v, int size) { + if (size == 2) { + v.dup2X2(); + } + else if (size == 1) { + v.dupX1(); + } + else { + throw new UnsupportedOperationException(); + } + } + public static void dup(@NotNull InstructionAdapter v, @NotNull Type topOfStack, @NotNull Type afterTop) { if (topOfStack.getSize() == 0 && afterTop.getSize() == 0) { return; diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/ComparableRangeLiteralRangeValue.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/ComparableRangeLiteralRangeValue.kt index bc2f6fd493b..ecba3122666 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/ComparableRangeLiteralRangeValue.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/ComparableRangeLiteralRangeValue.kt @@ -17,15 +17,27 @@ package org.jetbrains.kotlin.codegen.range import org.jetbrains.kotlin.codegen.ExpressionCodegen -import org.jetbrains.kotlin.codegen.range.forLoop.IteratorForLoopGenerator +import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.isClosedRangeContains -import org.jetbrains.kotlin.codegen.range.inExpression.InComparableRangeLiteralGenerator +import org.jetbrains.kotlin.codegen.range.comparison.ObjectComparisonGenerator +import org.jetbrains.kotlin.codegen.range.forLoop.IteratorForLoopGenerator +import org.jetbrains.kotlin.codegen.range.inExpression.InContinuousRangeExpressionGenerator import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtForExpression import org.jetbrains.kotlin.psi.KtSimpleNameExpression import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter + +class ComparableRangeLiteralRangeValue( + private val codegen: ExpressionCodegen, + rangeCall: ResolvedCall +) : CallIntrinsicRangeValue(rangeCall), BoundedValue { + private val from: ReceiverValue = rangeCall.extensionReceiver!! + private val to: KtExpression = ExpressionCodegen.getSingleArgumentExpression(rangeCall)!! -class ComparableRangeLiteralRangeValue(rangeCall: ResolvedCall): CallIntrinsicRangeValue(rangeCall) { override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) = IteratorForLoopGenerator(codegen, forExpression) @@ -33,5 +45,20 @@ class ComparableRangeLiteralRangeValue(rangeCall: ResolvedCall): RangeValue? { +private fun ExpressionCodegen.createIntrinsifiedRangeValueOrNull(rangeCall: ResolvedCall): RangeValue? { val rangeCallee = rangeCall.resultingDescriptor return when { @@ -96,7 +96,7 @@ private fun createIntrinsifiedRangeValueOrNull(rangeCall: ResolvedCall CharSequenceIndicesRangeValue(rangeCall) isComparableRangeTo(rangeCallee) -> - ComparableRangeLiteralRangeValue(rangeCall) + ComparableRangeLiteralRangeValue(this, rangeCall) else -> null } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/comparison/ComparisonGenerator.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/comparison/ComparisonGenerator.kt new file mode 100644 index 00000000000..dd0b6b022be --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/comparison/ComparisonGenerator.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2010-2017 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.codegen.range.comparison + +import org.jetbrains.org.objectweb.asm.Label +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter + +interface ComparisonGenerator { + val comparedType: Type + + fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label) + fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label) + fun jumpIfGreater(v: InstructionAdapter, label: Label) + fun jumpIfLess(v: InstructionAdapter, label: Label) +} + diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/comparison/FloatingPointComparisonGenerator.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/comparison/FloatingPointComparisonGenerator.kt new file mode 100644 index 00000000000..c76eda7f9b7 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/comparison/FloatingPointComparisonGenerator.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2017 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.codegen.range.comparison + +import org.jetbrains.org.objectweb.asm.Label +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter + +sealed class FloatingPointComparisonGenerator(override val comparedType: Type): ComparisonGenerator { + override fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label) { + v.cmpl(comparedType) + v.ifge(label) + } + + override fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label) { + v.cmpg(comparedType) + v.ifle(label) + } + + override fun jumpIfGreater(v: InstructionAdapter, label: Label) { + v.cmpl(comparedType) + v.ifgt(label) + } + + override fun jumpIfLess(v: InstructionAdapter, label: Label) { + v.cmpg(comparedType) + v.iflt(label) + } +} + +object FloatComparisonGenerator : FloatingPointComparisonGenerator(Type.FLOAT_TYPE) + +object DoubleComparisonGenerator : FloatingPointComparisonGenerator(Type.DOUBLE_TYPE) \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/comparison/IntComparisonGenerator.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/comparison/IntComparisonGenerator.kt new file mode 100644 index 00000000000..6c86a98829c --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/comparison/IntComparisonGenerator.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2010-2017 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.codegen.range.comparison + +import org.jetbrains.org.objectweb.asm.Label +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter + +object IntComparisonGenerator : ComparisonGenerator { + override val comparedType: Type = Type.INT_TYPE + + override fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label) { + v.ificmpge(label) + } + + override fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label) { + v.ificmple(label) + } + + override fun jumpIfGreater(v: InstructionAdapter, label: Label) { + v.ificmpgt(label) + } + + override fun jumpIfLess(v: InstructionAdapter, label: Label) { + v.ificmplt(label) + } +} \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/comparison/LongComparisonGenerator.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/comparison/LongComparisonGenerator.kt new file mode 100644 index 00000000000..a907815abc5 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/comparison/LongComparisonGenerator.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2010-2017 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.codegen.range.comparison + +import org.jetbrains.org.objectweb.asm.Label +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter + +object LongComparisonGenerator : ComparisonGenerator { + override val comparedType: Type = Type.LONG_TYPE + + override fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label) { + v.lcmp() + v.ifge(label) + } + + override fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label) { + v.lcmp() + v.ifle(label) + } + + override fun jumpIfGreater(v: InstructionAdapter, label: Label) { + v.lcmp() + v.ifgt(label) + } + + override fun jumpIfLess(v: InstructionAdapter, label: Label) { + v.lcmp() + v.iflt(label) + } +} \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/comparison/ObjectComparisonGenerator.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/comparison/ObjectComparisonGenerator.kt new file mode 100644 index 00000000000..0f5d930aba3 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/comparison/ObjectComparisonGenerator.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2010-2017 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.codegen.range.comparison + +import org.jetbrains.org.objectweb.asm.Label +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter + +object ObjectComparisonGenerator : ComparisonGenerator { + override val comparedType: Type = Type.getObjectType("java/lang/Comparable") + + override fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label) { + invokeCompare(v) + v.ifge(label) + } + + override fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label) { + invokeCompare(v) + v.ifle(label) + } + + override fun jumpIfGreater(v: InstructionAdapter, label: Label) { + invokeCompare(v) + v.ifgt(label) + } + + override fun jumpIfLess(v: InstructionAdapter, label: Label) { + invokeCompare(v) + v.iflt(label) + } + + private fun invokeCompare(v: InstructionAdapter) { + v.invokeinterface("java/lang/Comparable", "compareTo", "(Ljava/lang/Object;)I") + } +} \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/inExpression/AbstractInPrimitiveNumberRangeExpressionGenerator.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/inExpression/AbstractInPrimitiveNumberRangeExpressionGenerator.kt index ddf738a7b22..ebafb111222 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/inExpression/AbstractInPrimitiveNumberRangeExpressionGenerator.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/inExpression/AbstractInPrimitiveNumberRangeExpressionGenerator.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.codegen.ExpressionCodegen import org.jetbrains.kotlin.codegen.getClosedFloatingPointRangeElementType import org.jetbrains.kotlin.codegen.getPrimitiveRangeElementType +import org.jetbrains.kotlin.codegen.range.comparison.* import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.psi.KtSimpleNameExpression import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall @@ -39,62 +40,12 @@ abstract class AbstractInPrimitiveNumberRangeExpressionGenerator( ) { override val comparisonGenerator: ComparisonGenerator = when (asmElementType) { - Type.INT_TYPE, Type.SHORT_TYPE, Type.BYTE_TYPE, Type.CHAR_TYPE -> PrimitiveIntegerComparisonGenerator - Type.LONG_TYPE -> PrimitiveLongComparisonGenerator - Type.FLOAT_TYPE, Type.DOUBLE_TYPE -> PrimitiveFloatComparisonGenerator(asmElementType) + Type.INT_TYPE, Type.SHORT_TYPE, Type.BYTE_TYPE, Type.CHAR_TYPE -> IntComparisonGenerator + Type.LONG_TYPE -> LongComparisonGenerator + Type.FLOAT_TYPE -> FloatComparisonGenerator + Type.DOUBLE_TYPE -> DoubleComparisonGenerator else -> throw UnsupportedOperationException("Unexpected type: " + asmElementType) } - - private object PrimitiveIntegerComparisonGenerator : ComparisonGenerator { - override fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label) = v.ificmpge(label) - override fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label) = v.ificmple(label) - override fun jumpIfGreater(v: InstructionAdapter, label: Label) = v.ificmpgt(label) - override fun jumpIfLess(v: InstructionAdapter, label: Label) = v.ificmplt(label) - } - - private object PrimitiveLongComparisonGenerator : ComparisonGenerator { - override fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label) { - v.lcmp() - v.ifge(label) - } - - override fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label) { - v.lcmp() - v.ifle(label) - } - - override fun jumpIfGreater(v: InstructionAdapter, label: Label) { - v.lcmp() - v.ifgt(label) - } - - override fun jumpIfLess(v: InstructionAdapter, label: Label) { - v.lcmp() - v.iflt(label) - } - } - - private class PrimitiveFloatComparisonGenerator(val floatType: Type) : ComparisonGenerator { - override fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label) { - v.cmpg(floatType) - v.ifge(label) - } - - override fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label) { - v.cmpg(floatType) - v.ifle(label) - } - - override fun jumpIfGreater(v: InstructionAdapter, label: Label) { - v.cmpg(floatType) - v.ifgt(label) - } - - override fun jumpIfLess(v: InstructionAdapter, label: Label) { - v.cmpg(floatType) - v.iflt(label) - } - } } @@ -108,10 +59,9 @@ internal fun getAsmRangeElementTypeForPrimitiveRange(rangeCallee: CallableDescri val floatingPointElementType = getClosedFloatingPointRangeElementType(rangeType) ?: throw AssertionError("Unexpected range type: $rangeType") - if (KotlinBuiltIns.isDouble(floatingPointElementType)) - return Type.DOUBLE_TYPE - else if (KotlinBuiltIns.isFloat(floatingPointElementType)) - return Type.FLOAT_TYPE - else - throw AssertionError("Unexpected ClosedFloatingPointRange element type: $floatingPointElementType") + return when { + KotlinBuiltIns.isDouble(floatingPointElementType) -> Type.DOUBLE_TYPE + KotlinBuiltIns.isFloat(floatingPointElementType) -> Type.FLOAT_TYPE + else -> throw AssertionError("Unexpected ClosedFloatingPointRange element type: $floatingPointElementType") + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/inExpression/AbstractInRangeWithKnownBoundsExpressionGenerator.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/inExpression/AbstractInRangeWithKnownBoundsExpressionGenerator.kt index 08a8e5e4950..7c82f8ee57e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/inExpression/AbstractInRangeWithKnownBoundsExpressionGenerator.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/inExpression/AbstractInRangeWithKnownBoundsExpressionGenerator.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.codegen.range.inExpression import org.jetbrains.kotlin.codegen.* +import org.jetbrains.kotlin.codegen.range.comparison.ComparisonGenerator import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.KtSimpleNameExpression import org.jetbrains.org.objectweb.asm.Label @@ -35,13 +36,6 @@ abstract class AbstractInRangeWithKnownBoundsExpressionGenerator( protected abstract fun genLowBound(): StackValue protected abstract fun genHighBound(): StackValue - protected interface ComparisonGenerator { - fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label) - fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label) - fun jumpIfGreater(v: InstructionAdapter, label: Label) - fun jumpIfLess(v: InstructionAdapter, label: Label) - } - protected abstract val comparisonGenerator: ComparisonGenerator override fun generate(argument: StackValue): BranchedValue = diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/inExpression/InComparableRangeLiteralGenerator.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/inExpression/InComparableRangeLiteralGenerator.kt index ecc4907a507..a607865316f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/inExpression/InComparableRangeLiteralGenerator.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/inExpression/InComparableRangeLiteralGenerator.kt @@ -18,6 +18,8 @@ package org.jetbrains.kotlin.codegen.range.inExpression import org.jetbrains.kotlin.codegen.ExpressionCodegen import org.jetbrains.kotlin.codegen.StackValue +import org.jetbrains.kotlin.codegen.range.comparison.ComparisonGenerator +import org.jetbrains.kotlin.codegen.range.comparison.ObjectComparisonGenerator import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtSimpleNameExpression @@ -42,31 +44,5 @@ class InComparableRangeLiteralGenerator( override fun genHighBound(): StackValue = codegen.gen(to) - override val comparisonGenerator: ComparisonGenerator = ComparableComparisonGenerator - - private object ComparableComparisonGenerator : ComparisonGenerator { - override fun jumpIfGreaterOrEqual(v: InstructionAdapter, label: Label) { - invokeCompare(v) - v.ifge(label) - } - - override fun jumpIfLessOrEqual(v: InstructionAdapter, label: Label) { - invokeCompare(v) - v.ifle(label) - } - - override fun jumpIfGreater(v: InstructionAdapter, label: Label) { - invokeCompare(v) - v.ifgt(label) - } - - override fun jumpIfLess(v: InstructionAdapter, label: Label) { - invokeCompare(v) - v.iflt(label) - } - - private fun invokeCompare(v: InstructionAdapter) { - v.invokeinterface("java/lang/Comparable", "compareTo", "(Ljava/lang/Object;)I") - } - } + override val comparisonGenerator: ComparisonGenerator = ObjectComparisonGenerator } \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/range/inExpression/InContinuousRangeExpressionGenerator.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/inExpression/InContinuousRangeExpressionGenerator.kt new file mode 100644 index 00000000000..4a3d710a8c9 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/range/inExpression/InContinuousRangeExpressionGenerator.kt @@ -0,0 +1,128 @@ +/* + * Copyright 2010-2017 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.codegen.range.inExpression + +import org.jetbrains.kotlin.codegen.AsmUtil +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.comparison.ComparisonGenerator +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.KtSimpleNameExpression +import org.jetbrains.org.objectweb.asm.Label +import org.jetbrains.org.objectweb.asm.Opcodes +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter + +class InContinuousRangeExpressionGenerator( + operatorReference: KtSimpleNameExpression, + private val boundedValue: BoundedValue, + private val comparisonGenerator: ComparisonGenerator +) : InExpressionGenerator { + private val isNotIn = operatorReference.getReferencedNameElementType() == KtTokens.NOT_IN + + override fun generate(argument: StackValue): BranchedValue = + gen(argument).let { if (isNotIn) Invert(it) else it } + + private fun gen(argument: StackValue): BranchedValue = + object : BranchedValue(argument, null, comparisonGenerator.comparedType, Opcodes.IFEQ) { + override fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) { + if (jumpIfFalse) { + genJumpIfFalse(v, jumpLabel) + } + else { + genJumpIfTrue(v, jumpLabel) + } + } + + private fun genJumpIfTrue(v: InstructionAdapter, jumpLabel: Label) { + // if (arg is in range) goto jumpLabel + + val exitLabel1 = Label() + val exitLabel2 = Label() + + boundedValue.putHighLow(v, operandType) + arg1.put(operandType, v) + AsmUtil.dupx(v, operandType) + + // On stack: high arg low arg + // if (low bound is NOT satisfied) goto exitLabel1 + if (boundedValue.isLowInclusive) { + // low > arg + comparisonGenerator.jumpIfGreater(v, exitLabel1) + } + 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) { + // if (arg is NOT in range) goto jumpLabel + + val cmpHighLabel = Label() + + boundedValue.putHighLow(v, operandType) + arg1.put(operandType, v) + AsmUtil.dupx(v, operandType) + + // On stack: high arg low arg + // if ([low bound is satisfied]) goto cmpHighLabel + if (boundedValue.isLowInclusive) { + // low <= arg + comparisonGenerator.jumpIfLessOrEqual(v, cmpHighLabel) + } + else { + // low < arg + comparisonGenerator.jumpIfLess(v, cmpHighLabel) + } + + // 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) + } + } + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/ranges/contains/inRangeOfComparable.kt b/compiler/testData/codegen/box/ranges/contains/inRangeOfComparable.kt deleted file mode 100644 index 7596f5af439..00000000000 --- a/compiler/testData/codegen/box/ranges/contains/inRangeOfComparable.kt +++ /dev/null @@ -1,7 +0,0 @@ -// WITH_RUNTIME - -fun box(): String { - if ("z" in "Alpha" .. "Omega") return "Fail 1" - if ("Gamma" !in "Alpha" .. "Omega") return "Fail 2" - return "OK" -} \ No newline at end of file diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index f237bc17d22..091b04620a9 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -13279,12 +13279,6 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } - @TestMetadata("inRangeOfComparable.kt") - public void testInRangeOfComparable() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeOfComparable.kt"); - doTest(fileName); - } - @TestMetadata("inRangeWithCustomContains.kt") public void testInRangeWithCustomContains() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeWithCustomContains.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index bb5f263d793..39e1b0e7a0e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -13279,12 +13279,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } - @TestMetadata("inRangeOfComparable.kt") - public void testInRangeOfComparable() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeOfComparable.kt"); - doTest(fileName); - } - @TestMetadata("inRangeWithCustomContains.kt") public void testInRangeWithCustomContains() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeWithCustomContains.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index cdb272e7634..eccdcb6e6e5 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -13279,12 +13279,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } - @TestMetadata("inRangeOfComparable.kt") - public void testInRangeOfComparable() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeOfComparable.kt"); - doTest(fileName); - } - @TestMetadata("inRangeWithCustomContains.kt") public void testInRangeWithCustomContains() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeWithCustomContains.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 6f776ea66df..2505e5b305d 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -14935,12 +14935,6 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } - @TestMetadata("inRangeOfComparable.kt") - public void testInRangeOfComparable() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeOfComparable.kt"); - doTest(fileName); - } - @TestMetadata("inRangeWithCustomContains.kt") public void testInRangeWithCustomContains() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inRangeWithCustomContains.kt");