Introduce BoundedValue as a generalization of (low..high) range
Provide BoundedValue-based implementation of InExpressionGenerator, test it on range of comparable values. Drop unneeded test (range of comparables is already tested by ranges/contains/inComparableRanges.kt).
This commit is contained in:
@@ -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;
|
||||
|
||||
+31
-4
@@ -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<out CallableDescriptor>
|
||||
) : CallIntrinsicRangeValue(rangeCall), BoundedValue {
|
||||
private val from: ReceiverValue = rangeCall.extensionReceiver!!
|
||||
private val to: KtExpression = ExpressionCodegen.getSingleArgumentExpression(rangeCall)!!
|
||||
|
||||
class ComparableRangeLiteralRangeValue(rangeCall: ResolvedCall<out CallableDescriptor>): CallIntrinsicRangeValue(rangeCall) {
|
||||
override fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression) =
|
||||
IteratorForLoopGenerator(codegen, forExpression)
|
||||
|
||||
@@ -33,5 +45,20 @@ class ComparableRangeLiteralRangeValue(rangeCall: ResolvedCall<out CallableDescr
|
||||
isClosedRangeContains(resolvedCallForIn.resultingDescriptor)
|
||||
|
||||
override fun createIntrinsicInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression)=
|
||||
InComparableRangeLiteralGenerator(codegen, operatorReference, rangeCall)
|
||||
InContinuousRangeExpressionGenerator(operatorReference, this, ObjectComparisonGenerator)
|
||||
|
||||
override val instanceType: Type =
|
||||
codegen.asmType(rangeCall.resultingDescriptor.returnType!!)
|
||||
|
||||
override fun putInstance(v: InstructionAdapter) {
|
||||
codegen.invokeFunction(rangeCall.call, rangeCall, StackValue.none()).put(instanceType, v)
|
||||
}
|
||||
|
||||
override fun putHighLow(v: InstructionAdapter, type: Type) {
|
||||
codegen.gen(to).put(type, v)
|
||||
codegen.generateReceiverValue(from, false).put(type, v)
|
||||
}
|
||||
|
||||
override val isLowInclusive = true
|
||||
override val isHighInclusive = true
|
||||
}
|
||||
@@ -17,13 +17,35 @@
|
||||
package org.jetbrains.kotlin.codegen.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.codegen.range.forLoop.ForLoopGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.InExpressionGenerator
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
interface RangeValue {
|
||||
fun createForLoopGenerator(codegen: ExpressionCodegen, forExpression: KtForExpression): ForLoopGenerator
|
||||
|
||||
fun createInExpressionGenerator(codegen: ExpressionCodegen, operatorReference: KtSimpleNameExpression): InExpressionGenerator
|
||||
}
|
||||
|
||||
|
||||
interface BoundedValue {
|
||||
val instanceType: Type
|
||||
|
||||
fun putInstance(v: InstructionAdapter)
|
||||
|
||||
fun putHighLow(v: InstructionAdapter, type: Type)
|
||||
val isLowInclusive: Boolean
|
||||
val isHighInclusive: Boolean
|
||||
}
|
||||
|
||||
fun BoundedValue.asStackValue(): StackValue =
|
||||
object : StackValue(instanceType) {
|
||||
override fun putSelector(type: Type, v: InstructionAdapter) {
|
||||
putInstance(v)
|
||||
StackValue.onStack(instanceType).put(type, v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ private fun getResolvedCallForRangeExpression(
|
||||
}
|
||||
}
|
||||
|
||||
private fun createIntrinsifiedRangeValueOrNull(rangeCall: ResolvedCall<out CallableDescriptor>): RangeValue? {
|
||||
private fun ExpressionCodegen.createIntrinsifiedRangeValueOrNull(rangeCall: ResolvedCall<out CallableDescriptor>): RangeValue? {
|
||||
val rangeCallee = rangeCall.resultingDescriptor
|
||||
|
||||
return when {
|
||||
@@ -96,7 +96,7 @@ private fun createIntrinsifiedRangeValueOrNull(rangeCall: ResolvedCall<out Calla
|
||||
isCharSequenceIndices(rangeCallee) ->
|
||||
CharSequenceIndicesRangeValue(rangeCall)
|
||||
isComparableRangeTo(rangeCallee) ->
|
||||
ComparableRangeLiteralRangeValue(rangeCall)
|
||||
ComparableRangeLiteralRangeValue(this, rangeCall)
|
||||
else ->
|
||||
null
|
||||
}
|
||||
|
||||
+31
@@ -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)
|
||||
}
|
||||
|
||||
+47
@@ -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)
|
||||
+41
@@ -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)
|
||||
}
|
||||
}
|
||||
+45
@@ -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)
|
||||
}
|
||||
}
|
||||
+49
@@ -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")
|
||||
}
|
||||
}
|
||||
+10
-60
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
+1
-7
@@ -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 =
|
||||
|
||||
+3
-27
@@ -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
|
||||
}
|
||||
+128
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
-6
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user