diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 4e71a53dd96..4a268507ec5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -50,7 +50,7 @@ import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.codegen.when.SwitchCodegen; -import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil; +import org.jetbrains.kotlin.codegen.when.SwitchCodegenProvider; import org.jetbrains.kotlin.config.ApiVersion; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor; @@ -131,6 +131,7 @@ public class ExpressionCodegen extends KtVisitor impleme private final MemberCodegen parentCodegen; private final TailRecursionCodegen tailRecursionCodegen; public final CallGenerator defaultCallGenerator = new CallGenerator.DefaultCallGenerator(this); + private final SwitchCodegenProvider switchCodegenProvider; private final Stack blockStackElements = new Stack<>(); @@ -162,6 +163,7 @@ public class ExpressionCodegen extends KtVisitor impleme this.parentCodegen = parentCodegen; this.tailRecursionCodegen = new TailRecursionCodegen(context, this, this.v, state); + this.switchCodegenProvider = new SwitchCodegenProvider(this); } @Nullable @@ -4122,12 +4124,12 @@ The "returned" value of try expression with no finally is either the last expres Type resultType = isStatement ? Type.VOID_TYPE : expressionType(expression); return StackValue.operation(resultType, v -> { - SwitchCodegen switchCodegen = SwitchCodegenUtil.buildAppropriateSwitchCodegenIfPossible( - expression, isStatement, CodegenUtil.isExhaustive(bindingContext, expression, isStatement), this + SwitchCodegen switchCodegen = switchCodegenProvider.buildAppropriateSwitchCodegenIfPossible( + expression, isStatement, CodegenUtil.isExhaustive(bindingContext, expression, isStatement) ); if (switchCodegen != null) { switchCodegen.generate(); - return Unit.INSTANCE; + return null; } int subjectLocal = expr != null ? myFrameMap.enterTemp(subjectType) : -1; diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java index f8ece668c2a..bdd08c14b89 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java @@ -30,7 +30,7 @@ import org.jetbrains.kotlin.codegen.*; import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.TypeMapperUtilsKt; -import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil; +import org.jetbrains.kotlin.codegen.when.SwitchCodegenProvider; import org.jetbrains.kotlin.codegen.when.WhenByEnumsMapping; import org.jetbrains.kotlin.coroutines.CoroutineUtilKt; import org.jetbrains.kotlin.descriptors.*; @@ -83,7 +83,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid { private final JvmRuntimeTypes runtimeTypes; private final JvmFileClassesProvider fileClassesProvider; private final TypeMappingConfiguration typeMappingConfiguration; - private final boolean shouldInlineConstVals; + private final SwitchCodegenProvider switchCodegenProvider; public CodegenAnnotatingVisitor(@NotNull GenerationState state) { this.bindingTrace = state.getBindingTrace(); @@ -92,7 +92,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid { this.runtimeTypes = state.getJvmRuntimeTypes(); this.fileClassesProvider = state.getFileClassesProvider(); this.typeMappingConfiguration = state.getTypeMapper().getTypeMappingConfiguration(); - this.shouldInlineConstVals = state.getShouldInlineConstVals(); + this.switchCodegenProvider = new SwitchCodegenProvider(state); } @NotNull @@ -682,7 +682,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid { WhenByEnumsMapping mapping = new WhenByEnumsMapping(classDescriptor, currentClassName, fieldNumber); - for (ConstantValue constant : SwitchCodegenUtil.getAllConstants(expression, bindingContext, shouldInlineConstVals)) { + for (ConstantValue constant : switchCodegenProvider.getAllConstants(expression)) { if (constant instanceof NullValue) continue; assert constant instanceof EnumValue : "expression in when should be EnumValue"; @@ -696,10 +696,8 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid { private boolean isWhenWithEnums(@NotNull KtWhenExpression expression) { return WhenChecker.isWhenByEnum(expression, bindingContext) && - SwitchCodegenUtil.checkAllItemsAreConstantsSatisfying( + switchCodegenProvider.checkAllItemsAreConstantsSatisfying( expression, - bindingContext, - shouldInlineConstVals, constant -> constant instanceof EnumValue || constant instanceof NullValue ); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/when/SwitchCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/when/SwitchCodegen.java index 25776548b79..554b914d7a6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/when/SwitchCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/when/SwitchCodegen.java @@ -49,6 +49,8 @@ abstract public class SwitchCodegen { protected Label endLabel = new Label(); protected Label defaultLabel; + protected final SwitchCodegenProvider switchCodegenProvider; + public SwitchCodegen( @NotNull KtWhenExpression expression, boolean isStatement, boolean isExhaustive, @NotNull ExpressionCodegen codegen, @@ -59,6 +61,7 @@ abstract public class SwitchCodegen { this.isExhaustive = isExhaustive; this.codegen = codegen; this.bindingContext = codegen.getBindingContext(); + this.switchCodegenProvider = new SwitchCodegenProvider(codegen); this.subjectType = subjectType != null ? subjectType : codegen.expressionType(expression.getSubjectExpression()); resultType = isStatement ? Type.VOID_TYPE : codegen.expressionType(expression); @@ -100,7 +103,7 @@ abstract public class SwitchCodegen { for (KtWhenEntry entry : expression.getEntries()) { Label entryLabel = new Label(); - for (ConstantValue constant : SwitchCodegenUtil.getConstantsFromEntry(entry, bindingContext, codegen.getState().getShouldInlineConstVals())) { + for (ConstantValue constant : switchCodegenProvider.getConstantsFromEntry(entry)) { if (constant instanceof NullValue) continue; processConstant(constant, entryLabel); } @@ -158,7 +161,7 @@ abstract public class SwitchCodegen { private int findNullEntryIndex(@NotNull KtWhenExpression expression) { int entryIndex = 0; for (KtWhenEntry entry : expression.getEntries()) { - for (ConstantValue constant : SwitchCodegenUtil.getConstantsFromEntry(entry, bindingContext, codegen.getState().getShouldInlineConstVals())) { + for (ConstantValue constant : switchCodegenProvider.getConstantsFromEntry(entry)) { if (constant instanceof NullValue) { return entryIndex; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/when/SwitchCodegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/when/SwitchCodegenProvider.kt similarity index 55% rename from compiler/backend/src/org/jetbrains/kotlin/codegen/when/SwitchCodegenUtil.kt rename to compiler/backend/src/org/jetbrains/kotlin/codegen/when/SwitchCodegenProvider.kt index f113365d2c5..a7865f15d4c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/when/SwitchCodegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/when/SwitchCodegenProvider.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen.`when` import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.ExpressionCodegen import org.jetbrains.kotlin.codegen.binding.CodegenBinding +import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.constants.ConstantValue @@ -29,14 +30,16 @@ import org.jetbrains.org.objectweb.asm.Type import java.util.ArrayList -object SwitchCodegenUtil { - @JvmStatic - fun checkAllItemsAreConstantsSatisfying( - expression: KtWhenExpression, - bindingContext: BindingContext, - shouldInlineConstVals: Boolean, - predicate: Function1, Boolean> - ): Boolean = +class SwitchCodegenProvider +private constructor ( + private val bindingContext: BindingContext, + private val shouldInlineConstVals: Boolean, + private val codegen: ExpressionCodegen? +) { + constructor(state: GenerationState) : this(state.bindingContext, state.shouldInlineConstVals, null) + constructor(codegen: ExpressionCodegen) : this(codegen.bindingContext, codegen.state.shouldInlineConstVals, codegen) + + fun checkAllItemsAreConstantsSatisfying(expression: KtWhenExpression, predicate: Function1, Boolean>): Boolean = expression.entries.all { entry -> entry.conditions.all { condition -> if (condition !is KtWhenConditionWithExpression) return false @@ -46,33 +49,19 @@ object SwitchCodegenUtil { } } - @JvmStatic - fun getAllConstants( - expression: KtWhenExpression, - bindingContext: BindingContext, - shouldInlineConstVals: Boolean - ): Iterable?> = + fun getAllConstants(expression: KtWhenExpression): Iterable?> = ArrayList?>().apply { for (entry in expression.entries) { - addConstantsFromConditions(entry, bindingContext, shouldInlineConstVals) + addConstantsFromConditions(entry) } } - @JvmStatic - fun getConstantsFromEntry( - entry: KtWhenEntry, - bindingContext: BindingContext, - shouldInlineConstVals: Boolean - ): Iterable?> = + fun getConstantsFromEntry(entry: KtWhenEntry): Iterable?> = ArrayList?>().apply { - addConstantsFromConditions(entry, bindingContext, shouldInlineConstVals) + addConstantsFromConditions(entry) } - private fun ArrayList?>.addConstantsFromConditions( - entry: KtWhenEntry, - bindingContext: BindingContext, - shouldInlineConstVals: Boolean - ) { + private fun ArrayList?>.addConstantsFromConditions(entry: KtWhenEntry) { for (condition in entry.conditions) { if (condition !is KtWhenConditionWithExpression) continue val patternExpression = condition.expression ?: throw AssertionError("expression in when should not be null") @@ -80,16 +69,14 @@ object SwitchCodegenUtil { } } - @JvmStatic fun buildAppropriateSwitchCodegenIfPossible( expression: KtWhenExpression, isStatement: Boolean, - isExhaustive: Boolean, - codegen: ExpressionCodegen + isExhaustive: Boolean ): SwitchCodegen? { - val bindingContext = codegen.bindingContext - val shouldInlineConstVals = codegen.state.shouldInlineConstVals - if (!isThereConstantEntriesButNulls(expression, bindingContext, shouldInlineConstVals)) { + val codegen = codegen ?: throw AssertionError("Can't create SwitchCodegen in this context") + + if (!isThereConstantEntriesButNulls(expression)) { return null } @@ -100,37 +87,23 @@ object SwitchCodegenUtil { return when { mapping != null -> EnumSwitchCodegen(expression, isStatement, isExhaustive, codegen, mapping) - isIntegralConstantsSwitch(expression, subjectType, bindingContext, shouldInlineConstVals) -> + isIntegralConstantsSwitch(expression, subjectType) -> IntegralConstantsSwitchCodegen(expression, isStatement, isExhaustive, codegen) - isStringConstantsSwitch(expression, subjectType, bindingContext, shouldInlineConstVals) -> + isStringConstantsSwitch(expression, subjectType) -> StringSwitchCodegen(expression, isStatement, isExhaustive, codegen) else -> null } } - private fun isThereConstantEntriesButNulls( - expression: KtWhenExpression, - bindingContext: BindingContext, - shouldInlineConstVals: Boolean - ): Boolean = - getAllConstants(expression, bindingContext, shouldInlineConstVals).any { it != null && it !is NullValue } + private fun isThereConstantEntriesButNulls(expression: KtWhenExpression): Boolean = + getAllConstants(expression).any { it != null && it !is NullValue } - private fun isIntegralConstantsSwitch( - expression: KtWhenExpression, - subjectType: Type, - bindingContext: BindingContext, - shouldInlineConstVals: Boolean - ): Boolean = + private fun isIntegralConstantsSwitch(expression: KtWhenExpression, subjectType: Type): Boolean = AsmUtil.isIntPrimitive(subjectType) && - checkAllItemsAreConstantsSatisfying(expression, bindingContext, shouldInlineConstVals) { it is IntegerValueConstant<*> } + checkAllItemsAreConstantsSatisfying(expression) { it is IntegerValueConstant<*> } - private fun isStringConstantsSwitch( - expression: KtWhenExpression, - subjectType: Type, - bindingContext: BindingContext, - shouldInlineConstVals: Boolean - ): Boolean = + private fun isStringConstantsSwitch(expression: KtWhenExpression, subjectType: Type): Boolean = subjectType.className == String::class.java.name && - checkAllItemsAreConstantsSatisfying(expression, bindingContext, shouldInlineConstVals) { it is StringValue || it is NullValue } + checkAllItemsAreConstantsSatisfying(expression) { it is StringValue || it is NullValue } }