Turn SwitchCodegenUtil into a class

This commit is contained in:
Dmitry Petrov
2017-08-04 17:58:46 +03:00
parent 435cfeea0a
commit 656f8bb5cf
4 changed files with 44 additions and 68 deletions
@@ -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<StackValue, StackValue> impleme
private final MemberCodegen<?> parentCodegen;
private final TailRecursionCodegen tailRecursionCodegen;
public final CallGenerator defaultCallGenerator = new CallGenerator.DefaultCallGenerator(this);
private final SwitchCodegenProvider switchCodegenProvider;
private final Stack<BlockStackElement> blockStackElements = new Stack<>();
@@ -162,6 +163,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> 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;
@@ -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<Type> 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
);
}
@@ -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;
}
@@ -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<ConstantValue<*>, 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<ConstantValue<*>, 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<ConstantValue<*>?> =
fun getAllConstants(expression: KtWhenExpression): Iterable<ConstantValue<*>?> =
ArrayList<ConstantValue<*>?>().apply {
for (entry in expression.entries) {
addConstantsFromConditions(entry, bindingContext, shouldInlineConstVals)
addConstantsFromConditions(entry)
}
}
@JvmStatic
fun getConstantsFromEntry(
entry: KtWhenEntry,
bindingContext: BindingContext,
shouldInlineConstVals: Boolean
): Iterable<ConstantValue<*>?> =
fun getConstantsFromEntry(entry: KtWhenEntry): Iterable<ConstantValue<*>?> =
ArrayList<ConstantValue<*>?>().apply {
addConstantsFromConditions(entry, bindingContext, shouldInlineConstVals)
addConstantsFromConditions(entry)
}
private fun ArrayList<ConstantValue<*>?>.addConstantsFromConditions(
entry: KtWhenEntry,
bindingContext: BindingContext,
shouldInlineConstVals: Boolean
) {
private fun ArrayList<ConstantValue<*>?>.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 }
}