Optimize const vals by inlining them at use sites

#KT-11734 Fixed
 #KT-13570 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2016-12-05 12:02:52 +03:00
parent 8c1e165f18
commit 0134b8819b
28 changed files with 210 additions and 136 deletions
@@ -50,10 +50,7 @@ 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.config.CommonConfigurationKeys;
import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl;
import org.jetbrains.kotlin.config.*;
import org.jetbrains.kotlin.coroutines.CoroutineUtilKt;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
@@ -1438,14 +1435,17 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
@Override
public StackValue visitConstantExpression(@NotNull KtConstantExpression expression, StackValue receiver) {
ConstantValue<?> compileTimeValue = getPrimitiveOrStringCompileTimeConstant(expression, bindingContext);
ConstantValue<?> compileTimeValue = getPrimitiveOrStringCompileTimeConstant(expression, bindingContext, state.getShouldInlineConstVals());
assert compileTimeValue != null;
return StackValue.constant(compileTimeValue.getValue(), expressionType(expression));
}
@Nullable
public static ConstantValue<?> getPrimitiveOrStringCompileTimeConstant(@NotNull KtExpression expression, @NotNull BindingContext bindingContext) {
ConstantValue<?> constant = getCompileTimeConstant(expression, bindingContext, false);
public static ConstantValue<?> getPrimitiveOrStringCompileTimeConstant(
@NotNull KtExpression expression,
@NotNull BindingContext bindingContext,
boolean shouldInlineConstVals) {
ConstantValue<?> constant = getCompileTimeConstant(expression, bindingContext, false, shouldInlineConstVals);
if (constant == null || ConstantExpressionEvaluatorKt.isStandaloneOnlyConstant(constant)) {
return null;
}
@@ -1453,22 +1453,26 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
@Nullable
public static ConstantValue<?> getCompileTimeConstant(@NotNull KtExpression expression, @NotNull BindingContext bindingContext) {
return getCompileTimeConstant(expression, bindingContext, false);
public static ConstantValue<?> getCompileTimeConstant(
@NotNull KtExpression expression,
@NotNull BindingContext bindingContext,
boolean shouldInlineConstVals) {
return getCompileTimeConstant(expression, bindingContext, false, shouldInlineConstVals);
}
@Nullable
public static ConstantValue<?> getCompileTimeConstant(
@NotNull KtExpression expression,
@NotNull final BindingContext bindingContext,
boolean takeUpConstValsAsConst
boolean takeUpConstValsAsConst,
boolean shouldInlineConstVals
) {
CompileTimeConstant<?> compileTimeValue = ConstantExpressionEvaluator.getConstant(expression, bindingContext);
if (compileTimeValue == null || compileTimeValue.getUsesNonConstValAsConstant()) {
return null;
}
if (!takeUpConstValsAsConst && compileTimeValue.getUsesVariableAsConstant()) {
if (!shouldInlineConstVals && !takeUpConstValsAsConst && compileTimeValue.getUsesVariableAsConstant()) {
final Ref<Boolean> containsNonInlinedVals = new Ref<Boolean>(false);
KtVisitor constantChecker = new KtVisitor() {
@Override
@@ -2607,14 +2611,10 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
boolean skipPropertyAccessors;
PropertyDescriptor originalPropertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor);
LanguageVersionSettings languageVersionSettings = state.getConfiguration().get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS);
if (languageVersionSettings == null) {
languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT;
}
if (fieldAccessorKind != FieldAccessorKind.NORMAL) {
int flags = AsmUtil.getVisibilityForBackingField(propertyDescriptor, isDelegatedProperty);
boolean isInlinedConst = propertyDescriptor.isConst() && languageVersionSettings.supportsFeature(LanguageFeature.InlineConstVals);
boolean isInlinedConst = propertyDescriptor.isConst() && state.getShouldInlineConstVals();
skipPropertyAccessors = isInlinedConst || (flags & ACC_PRIVATE) == 0 || skipAccessorsForPrivateFieldInOuterClass;
if (!skipPropertyAccessors) {
@@ -2635,7 +2635,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
if (!skipPropertyAccessors) {
if (!couldUseDirectAccessToProperty(propertyDescriptor, true, isDelegatedProperty, context, languageVersionSettings)) {
if (!couldUseDirectAccessToProperty(propertyDescriptor, true, isDelegatedProperty, context, state.getShouldInlineConstVals())) {
propertyDescriptor = context.getAccessorForSuperCallIfNeeded(propertyDescriptor, superCallTarget);
propertyDescriptor = context.accessibleDescriptor(propertyDescriptor, superCallTarget);
@@ -2649,7 +2649,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
if (propertyDescriptor.isVar()) {
PropertySetterDescriptor setter = propertyDescriptor.getSetter();
if (setter != null &&
!couldUseDirectAccessToProperty(propertyDescriptor, false, isDelegatedProperty, context, languageVersionSettings) &&
!couldUseDirectAccessToProperty(propertyDescriptor, false, isDelegatedProperty, context, state.getShouldInlineConstVals()) &&
!isConstOrHasJvmFieldAnnotation(propertyDescriptor)) {
callableSetter = typeMapper.mapToCallableMethod(setter, isSuper);
}
@@ -3523,7 +3523,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
expression.getRight(), reference);
}
else {
ConstantValue<?> compileTimeConstant = getPrimitiveOrStringCompileTimeConstant(expression, bindingContext);
ConstantValue<?> compileTimeConstant = getPrimitiveOrStringCompileTimeConstant(expression, bindingContext, state.getShouldInlineConstVals());
if (compileTimeConstant != null) {
return StackValue.constant(compileTimeConstant.getValue(), expressionType(expression));
}
@@ -3666,7 +3666,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
private boolean isIntZero(KtExpression expr, Type exprType) {
ConstantValue<?> exprValue = getPrimitiveOrStringCompileTimeConstant(expr, bindingContext);
ConstantValue<?> exprValue = getPrimitiveOrStringCompileTimeConstant(expr, bindingContext, state.getShouldInlineConstVals());
return isIntPrimitive(exprType) && exprValue != null && Integer.valueOf(0).equals(exprValue.getValue());
}
@@ -3796,7 +3796,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
public void invokeAppend(KtExpression expr) {
ConstantValue<?> compileTimeConstant = getPrimitiveOrStringCompileTimeConstant(expr, bindingContext);
ConstantValue<?> compileTimeConstant = getPrimitiveOrStringCompileTimeConstant(expr, bindingContext, state.getShouldInlineConstVals());
if (compileTimeConstant == null && expr instanceof KtBinaryExpression) {
KtBinaryExpression binaryExpression = (KtBinaryExpression) expr;
@@ -3839,7 +3839,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
@Override
public StackValue visitPrefixExpression(@NotNull KtPrefixExpression expression, @NotNull StackValue receiver) {
ConstantValue<?> compileTimeConstant = getPrimitiveOrStringCompileTimeConstant(expression, bindingContext);
ConstantValue<?> compileTimeConstant = getPrimitiveOrStringCompileTimeConstant(expression, bindingContext, state.getShouldInlineConstVals());
if (compileTimeConstant != null) {
return StackValue.constant(compileTimeConstant.getValue(), expressionType(expression));
}
@@ -649,12 +649,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
private Type genPropertyOnStack(InstructionAdapter iv, MethodContext context, @NotNull PropertyDescriptor propertyDescriptor, int index) {
iv.load(index, classAsmType);
LanguageVersionSettings settings = state.getConfiguration().get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS);
if (settings == null) {
settings = LanguageVersionSettingsImpl.DEFAULT;
}
if (couldUseDirectAccessToProperty(propertyDescriptor, /* forGetter = */ true,
/* isDelegated = */ false, context, settings)) {
/* isDelegated = */ false, context, state.getShouldInlineConstVals())) {
Type type = typeMapper.mapType(propertyDescriptor.getType());
String fieldName = ((FieldOwnerContext) context.getParentContext()).getFieldName(propertyDescriptor, false);
iv.getfield(classAsmType.getInternalName(), fieldName, type.getDescriptor());
@@ -185,9 +185,9 @@ public class JvmCodegenUtil {
boolean forGetter,
boolean isDelegated,
@NotNull MethodContext contextBeforeInline,
@NotNull LanguageVersionSettings languageVersionSettings
boolean shouldInlineConstVals
) {
if (languageVersionSettings.supportsFeature(LanguageFeature.InlineConstVals) && property.isConst()) return true;
if (shouldInlineConstVals && property.isConst()) return true;
if (KotlinTypeMapper.isAccessor(property)) return false;
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.codegen.inline.*;
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
@@ -461,7 +462,7 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
KtExpression initializer = property.getInitializer();
ConstantValue<?> initializerValue =
initializer != null ? ExpressionCodegen.getCompileTimeConstant(initializer, bindingContext) : null;
initializer != null ? ExpressionCodegen.getCompileTimeConstant(initializer, bindingContext, state.getShouldInlineConstVals()) : null;
// we must write constant values for fields in light classes,
// because Java's completion for annotation arguments uses this information
if (initializerValue == null) return state.getClassBuilderMode().generateBodies;
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.codegen.annotation.AnnotatedWithFakeAnnotations;
import org.jetbrains.kotlin.codegen.context.*;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotated;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationSplitter;
@@ -228,7 +229,8 @@ public class PropertyCodegen {
KtExpression defaultValue = p.getDefaultValue();
if (defaultValue != null) {
ConstantValue<?> constant = ExpressionCodegen.getCompileTimeConstant(defaultValue, bindingContext, true);
ConstantValue<?> constant = ExpressionCodegen.getCompileTimeConstant(
defaultValue, bindingContext, true, state.getShouldInlineConstVals());
assert !state.getClassBuilderMode().generateBodies || constant != null
: "Default value for annotation parameter should be compile time value: " + defaultValue.getText();
if (constant != null) {
@@ -30,10 +30,11 @@ import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods;
import org.jetbrains.kotlin.codegen.intrinsics.JavaClassProperty;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.ValueArgument;
import org.jetbrains.kotlin.resolve.BindingContext;
@@ -1199,7 +1200,7 @@ public abstract class StackValue {
if (getter == null) {
assert fieldName != null : "Property should have either a getter or a field name: " + descriptor;
assert backingFieldOwner != null : "Property should have either a getter or a backingFieldOwner: " + descriptor;
if (inlineJavaConstantIfNeeded(type, v)) return;
if (inlineConstantIfNeeded(type, v)) return;
v.visitFieldInsn(isStaticPut ? GETSTATIC : GETFIELD,
backingFieldOwner.getInternalName(), fieldName, this.type.getDescriptor());
@@ -1227,15 +1228,24 @@ public abstract class StackValue {
}
}
private boolean inlineJavaConstantIfNeeded(@NotNull Type type, @NotNull InstructionAdapter v) {
if (!JvmCodegenUtil.isInlinedJavaConstProperty(descriptor)) return false;
private boolean inlineConstantIfNeeded(@NotNull Type type, @NotNull InstructionAdapter v) {
if (JvmCodegenUtil.isInlinedJavaConstProperty(descriptor)) {
return inlineConstant(type, v);
}
if (descriptor.isConst() && codegen.getState().getShouldInlineConstVals()) {
return inlineConstant(type, v);
}
return false;
}
private boolean inlineConstant(@NotNull Type type, @NotNull InstructionAdapter v) {
assert AsmUtil.isPrimitive(this.type) || AsmTypes.JAVA_STRING_TYPE.equals(this.type) :
"Java const property should have primitive or string type: " + descriptor;
assert isStaticPut : "Java const property should be static" + descriptor;
"Const property should have primitive or string type: " + descriptor;
assert isStaticPut : "Const property should be static" + descriptor;
JavaPropertyDescriptor javaPropertyDescriptor = (JavaPropertyDescriptor) descriptor;
ConstantValue<?> constantValue = javaPropertyDescriptor.getCompileTimeInitializer();
ConstantValue<?> constantValue = descriptor.getCompileTimeInitializer();
if (constantValue == null) return false;
Object value = constantValue.getValue();
@@ -33,6 +33,7 @@ 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.WhenByEnumsMapping;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.coroutines.CoroutineUtilKt;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
@@ -83,6 +84,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
private final JvmRuntimeTypes runtimeTypes;
private final JvmFileClassesProvider fileClassesProvider;
private final TypeMappingConfiguration<Type> typeMappingConfiguration;
private final boolean shouldInlineConstVals;
public CodegenAnnotatingVisitor(@NotNull GenerationState state) {
this.bindingTrace = state.getBindingTrace();
@@ -91,6 +93,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
this.runtimeTypes = state.getJvmRuntimeTypes();
this.fileClassesProvider = state.getFileClassesProvider();
this.typeMappingConfiguration = state.getTypeMapper().getTypeMappingConfiguration();
this.shouldInlineConstVals = state.getShouldInlineConstVals();
}
@NotNull
@@ -645,7 +648,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
WhenByEnumsMapping mapping = new WhenByEnumsMapping(classDescriptor, currentClassName, fieldNumber);
for (ConstantValue<?> constant : SwitchCodegenUtil.getAllConstants(expression, bindingContext)) {
for (ConstantValue<?> constant : SwitchCodegenUtil.getAllConstants(expression, bindingContext, shouldInlineConstVals)) {
if (constant instanceof NullValue) continue;
assert constant instanceof EnumValue : "expression in when should be EnumValue";
@@ -662,6 +665,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
SwitchCodegenUtil.checkAllItemsAreConstantsSatisfying(
expression,
bindingContext,
shouldInlineConstVals,
new Function1<ConstantValue<?>, Boolean>() {
@Override
public Boolean invoke(@NotNull ConstantValue<?> constant) {
@@ -30,10 +30,7 @@ import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
import org.jetbrains.kotlin.codegen.inline.InlineCache
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
import org.jetbrains.kotlin.codegen.optimization.OptimizationClassBuilderFactory
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
import org.jetbrains.kotlin.diagnostics.Diagnostic
@@ -169,6 +166,11 @@ class GenerationState @JvmOverloads constructor(
val generateParametersMetadata: Boolean = configuration.getBoolean(JVMConfigurationKeys.PARAMETERS_METADATA)
val shouldInlineConstVals = run {
val settings = configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS) ?: LanguageVersionSettingsImpl.DEFAULT
settings.supportsFeature(LanguageFeature.InlineConstVals)
}
init {
this.interceptedBuilderFactory = builderFactory
.wrapWith(
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen.when;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.codegen.ExpressionCodegen;
import org.jetbrains.kotlin.codegen.FrameMap;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.psi.KtWhenEntry;
import org.jetbrains.kotlin.psi.KtWhenExpression;
import org.jetbrains.kotlin.resolve.BindingContext;
@@ -98,7 +99,7 @@ abstract public class SwitchCodegen {
for (KtWhenEntry entry : expression.getEntries()) {
Label entryLabel = new Label();
for (ConstantValue<?> constant : SwitchCodegenUtil.getConstantsFromEntry(entry, bindingContext)) {
for (ConstantValue<?> constant : SwitchCodegenUtil.getConstantsFromEntry(entry, bindingContext, codegen.getState().getShouldInlineConstVals())) {
if (constant instanceof NullValue) continue;
processConstant(constant, entryLabel);
}
@@ -156,7 +157,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)) {
for (ConstantValue<?> constant : SwitchCodegenUtil.getConstantsFromEntry(entry, bindingContext, codegen.getState().getShouldInlineConstVals())) {
if (constant instanceof NullValue) {
return entryIndex;
}
@@ -36,6 +36,7 @@ public class SwitchCodegenUtil {
public static boolean checkAllItemsAreConstantsSatisfying(
@NotNull KtWhenExpression expression,
@NotNull BindingContext bindingContext,
boolean shouldInlineConstVals,
Function1<ConstantValue<?>, Boolean> predicate
) {
for (KtWhenEntry entry : expression.getEntries()) {
@@ -49,7 +50,7 @@ public class SwitchCodegenUtil {
if (patternExpression == null) return false;
ConstantValue<?> constant = ExpressionCodegen.getCompileTimeConstant(patternExpression, bindingContext);
ConstantValue<?> constant = ExpressionCodegen.getCompileTimeConstant(patternExpression, bindingContext, shouldInlineConstVals);
if (constant == null || !predicate.invoke(constant)) {
return false;
}
@@ -62,12 +63,13 @@ public class SwitchCodegenUtil {
@NotNull
public static Iterable<ConstantValue<?>> getAllConstants(
@NotNull KtWhenExpression expression,
@NotNull BindingContext bindingContext
@NotNull BindingContext bindingContext,
boolean shouldInlineConstVals
) {
List<ConstantValue<?>> result = new ArrayList<ConstantValue<?>>();
for (KtWhenEntry entry : expression.getEntries()) {
addConstantsFromEntry(result, entry, bindingContext);
addConstantsFromEntry(result, entry, bindingContext, shouldInlineConstVals);
}
return result;
@@ -76,7 +78,8 @@ public class SwitchCodegenUtil {
private static void addConstantsFromEntry(
@NotNull List<ConstantValue<?>> result,
@NotNull KtWhenEntry entry,
@NotNull BindingContext bindingContext
@NotNull BindingContext bindingContext,
boolean shouldInlineConstVals
) {
for (KtWhenCondition condition : entry.getConditions()) {
if (!(condition instanceof KtWhenConditionWithExpression)) continue;
@@ -84,17 +87,18 @@ public class SwitchCodegenUtil {
KtExpression patternExpression = ((KtWhenConditionWithExpression) condition).getExpression();
assert patternExpression != null : "expression in when should not be null";
result.add(ExpressionCodegen.getCompileTimeConstant(patternExpression, bindingContext));
result.add(ExpressionCodegen.getCompileTimeConstant(patternExpression, bindingContext, shouldInlineConstVals));
}
}
@NotNull
public static Iterable<ConstantValue<?>> getConstantsFromEntry(
@NotNull KtWhenEntry entry,
@NotNull BindingContext bindingContext
@NotNull BindingContext bindingContext,
boolean shouldInlineConstVals
) {
List<ConstantValue<?>> result = new ArrayList<ConstantValue<?>>();
addConstantsFromEntry(result, entry, bindingContext);
addConstantsFromEntry(result, entry, bindingContext, shouldInlineConstVals);
return result;
}
@@ -106,7 +110,8 @@ public class SwitchCodegenUtil {
@NotNull ExpressionCodegen codegen
) {
BindingContext bindingContext = codegen.getBindingContext();
if (!isThereConstantEntriesButNulls(expression, bindingContext)) {
boolean shouldInlineConstVals = codegen.getState().getShouldInlineConstVals();
if (!isThereConstantEntriesButNulls(expression, bindingContext, shouldInlineConstVals)) {
return null;
}
@@ -118,11 +123,11 @@ public class SwitchCodegenUtil {
return new EnumSwitchCodegen(expression, isStatement, isExhaustive, codegen, mapping);
}
if (isIntegralConstantsSwitch(expression, subjectType, bindingContext)) {
if (isIntegralConstantsSwitch(expression, subjectType, bindingContext, shouldInlineConstVals)) {
return new IntegralConstantsSwitchCodegen(expression, isStatement, isExhaustive, codegen);
}
if (isStringConstantsSwitch(expression, subjectType, bindingContext)) {
if (isStringConstantsSwitch(expression, subjectType, bindingContext, shouldInlineConstVals)) {
return new StringSwitchCodegen(expression, isStatement, isExhaustive, codegen);
}
@@ -131,9 +136,10 @@ public class SwitchCodegenUtil {
private static boolean isThereConstantEntriesButNulls(
@NotNull KtWhenExpression expression,
@NotNull BindingContext bindingContext
@NotNull BindingContext bindingContext,
boolean shouldInlineConstVals
) {
for (ConstantValue<?> constant : getAllConstants(expression, bindingContext)) {
for (ConstantValue<?> constant : getAllConstants(expression, bindingContext, shouldInlineConstVals)) {
if (constant != null && !(constant instanceof NullValue)) return true;
}
@@ -143,7 +149,8 @@ public class SwitchCodegenUtil {
private static boolean isIntegralConstantsSwitch(
@NotNull KtWhenExpression expression,
@NotNull Type subjectType,
@NotNull BindingContext bindingContext
@NotNull BindingContext bindingContext,
boolean shouldInlineConstVals
) {
int typeSort = subjectType.getSort();
@@ -151,7 +158,7 @@ public class SwitchCodegenUtil {
return false;
}
return checkAllItemsAreConstantsSatisfying(expression, bindingContext, new Function1<ConstantValue<?>, Boolean>() {
return checkAllItemsAreConstantsSatisfying(expression, bindingContext, shouldInlineConstVals, new Function1<ConstantValue<?>, Boolean>() {
@Override
public Boolean invoke(
@NotNull ConstantValue<?> constant
@@ -164,14 +171,15 @@ public class SwitchCodegenUtil {
private static boolean isStringConstantsSwitch(
@NotNull KtWhenExpression expression,
@NotNull Type subjectType,
@NotNull BindingContext bindingContext
@NotNull BindingContext bindingContext,
boolean shouldInlineConstVals
) {
if (!subjectType.getClassName().equals(String.class.getName())) {
return false;
}
return checkAllItemsAreConstantsSatisfying(expression, bindingContext, new Function1<ConstantValue<?>, Boolean>() {
return checkAllItemsAreConstantsSatisfying(expression, bindingContext, shouldInlineConstVals, new Function1<ConstantValue<?>, Boolean>() {
@Override
public Boolean invoke(
@NotNull ConstantValue<?> constant
@@ -89,7 +89,8 @@ class FunctionCodegen(val irFunction: IrFunction, val classCodegen: ClassCodegen
val source = directMember.source
(source.getPsi() as? KtParameter)?.defaultValue?.apply {
val defaultValue = this
val constant = org.jetbrains.kotlin.codegen.ExpressionCodegen.getCompileTimeConstant(defaultValue, state.bindingContext, true)
val constant = org.jetbrains.kotlin.codegen.ExpressionCodegen.getCompileTimeConstant(
defaultValue, state.bindingContext, true, state.shouldInlineConstVals)
assert(!state.classBuilderMode.generateBodies || constant != null) { "Default value for annotation parameter should be compile time value: " + defaultValue.getText() }
if (constant != null) {
val annotationCodegen = AnnotationCodegen.forAnnotationDefaultValue(methodVisitor, classCodegen, state.typeMapper)
@@ -1,43 +0,0 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
//WITH_RUNTIME
//FULL_JDK
//NOTE this test should be removed if Kotlin const properties will became inlined
import java.lang.reflect.Field
import java.lang.reflect.Modifier
object ThingTemplate {
const val prop = 0
}
class ThingVal {
val prop = ThingTemplate.prop
}
class ThingVar {
var prop = ThingTemplate.prop
}
fun box() : String {
val template = ThingTemplate;
val javaClass = ThingTemplate::class.java
val field = javaClass.getDeclaredField("prop")!!
field.isAccessible = true
val modifiersField = Field::class.java!!.getDeclaredField("modifiers")
modifiersField.isAccessible = true
modifiersField.setInt(field, field.modifiers and Modifier.FINAL.inv())
field.set(null, 1)
val thingVal = ThingVal()
if (thingVal.prop != 1) return "fail 1"
val thingVar = ThingVar()
if (thingVar.prop != 1) return "fail 2"
return "OK"
}
@@ -1,3 +1,5 @@
// LANGUAGE_VERSION: 1.0
const val z = 0
fun a() {
@@ -1,3 +1,5 @@
// LANGUAGE_VERSION: 1.0
const val z = 0
fun a() {
@@ -0,0 +1,9 @@
const val one = 1
const val two = 2
fun test1() {
if (!(one < two)) {
val p = 1
}
}
// 0 IF
@@ -1,3 +1,5 @@
// LANGUAGE_VERSION: 1.0
const val one = 1
const val two = 2
@@ -0,0 +1,17 @@
const val A = 10
private const val B = 20
object Constants {
const val C = 30
}
fun foo(state: Int) {
when (state) {
A -> return
B -> return
Constants.C -> return
else -> return
}
}
// 1 LOOKUPSWITCH
@@ -0,0 +1,20 @@
object Constants {
const val A = 30
const val B = 40
}
class ClassConstants {
companion object {
const val C = 50
}
}
fun foo(state: Int) {
when (state) {
Constants.A -> return
Constants.B -> return
ClassConstants.C -> return
else -> return
}
}
// 1 LOOKUPSWITCH
@@ -0,0 +1,16 @@
const val A = 10
private const val B = 20
object Constants {
const val C = 30
}
fun foo(state: Int) {
when (state) {
A -> return
B -> return
else -> return
}
}
// 1 LOOKUPSWITCH
@@ -0,0 +1,12 @@
const val y = "cde"
fun foo(x : String) : String {
when (x) {
"abc", "${y}" -> return "abc_cde"
"e" + "fg", "ghi" -> return "efg_ghi"
}
return "other"
}
// 1 LOOKUPSWITCH
@@ -1,3 +1,5 @@
// LANGUAGE_VERSION: 1.0
const val y = "cde"
fun foo(x : String) : String {
@@ -38,8 +38,7 @@
{"visibility": "public", "declaration": "fun publicFun(): kotlin.Unit", "name": "publicFun", "desc": "()V"},
{"visibility": "internal", "declaration": "fun internalFun(param1: kotlin.Int): kotlin.Unit", "name": "internalFun", "desc": "(I)V"},
{"visibility": "private", "declaration": "fun privateFun(x: kotlin.Any): kotlin.Unit", "name": "privateFun$MultifileFacade__Part2Kt", "desc": "(Ljava/lang/Object;)V"},
{"visibility": "private", "declaration": "fun privateFun(x: kotlin.Any): kotlin.Unit", "name": "access$privateFun", "desc": "(Ljava/lang/Object;)V"},
{"visibility": "private", "declaration": "fun <get-privateConst>(): kotlin.Int", "name": "access$getPrivateConst$p", "desc": "()I"}
{"visibility": "private", "declaration": "fun privateFun(x: kotlin.Any): kotlin.Unit", "name": "access$privateFun", "desc": "(Ljava/lang/Object;)V"}
]
},
{
@@ -42,8 +42,7 @@
{"visibility": "private", "declaration": "fun privateFun(x: kotlin.Any?): kotlin.Unit", "name": "access$privateFun", "desc": "(Ljava/lang/Object;)V"},
{"visibility": "private", "declaration": "fun <get-privateVal>(): kotlin.Any?", "name": "access$getPrivateVal$p", "desc": "()Ljava/lang/Object;"},
{"visibility": "private", "declaration": "fun <get-privateVar>(): kotlin.Any?", "name": "access$getPrivateVar$p", "desc": "()Ljava/lang/Object;"},
{"visibility": "private", "declaration": "fun <set-privateVar>(<set-?>: kotlin.Any?): kotlin.Unit", "name": "access$setPrivateVar$p", "desc": "(Ljava/lang/Object;)V"},
{"visibility": "private", "declaration": "fun <get-privateConst>(): kotlin.Int", "name": "access$getPrivateConst$p", "desc": "()I"}
{"visibility": "private", "declaration": "fun <set-privateVar>(<set-?>: kotlin.Any?): kotlin.Unit", "name": "access$setPrivateVar$p", "desc": "(Ljava/lang/Object;)V"}
]
}
]
@@ -11225,12 +11225,6 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("kt12200Const.kt")
public void testKt12200Const() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/kt12200Const.kt");
doTest(fileName);
}
@TestMetadata("kt1398.kt")
public void testKt1398() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/kt1398.kt");
@@ -11225,12 +11225,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("kt12200Const.kt")
public void testKt12200Const() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/kt12200Const.kt");
doTest(fileName);
}
@TestMetadata("kt1398.kt")
public void testKt1398() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/kt1398.kt");
@@ -1256,6 +1256,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/lazyCodegen"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("inlineConstInsideComparison.kt")
public void testInlineConstInsideComparison() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/lazyCodegen/inlineConstInsideComparison.kt");
doTest(fileName);
}
@TestMetadata("negateConst.kt")
public void testNegateConst() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/lazyCodegen/negateConst.kt");
@@ -1562,17 +1568,35 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
doTest(fileName);
}
@TestMetadata("inlineConstValsInsideWhen.kt")
public void testInlineConstValsInsideWhen() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/when/inlineConstValsInsideWhen.kt");
doTest(fileName);
}
@TestMetadata("integralWhenWithNoInlinedConstants.kt")
public void testIntegralWhenWithNoInlinedConstants() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/when/integralWhenWithNoInlinedConstants.kt");
doTest(fileName);
}
@TestMetadata("qualifiedConstValsInsideWhen.kt")
public void testQualifiedConstValsInsideWhen() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/when/qualifiedConstValsInsideWhen.kt");
doTest(fileName);
}
@TestMetadata("sealedWhenInitialization.kt")
public void testSealedWhenInitialization() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/when/sealedWhenInitialization.kt");
doTest(fileName);
}
@TestMetadata("simpleConstValsInsideWhen.kt")
public void testSimpleConstValsInsideWhen() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/when/simpleConstValsInsideWhen.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/bytecodeText/whenEnumOptimization")
@@ -1676,6 +1700,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
doTest(fileName);
}
@TestMetadata("inlineStringConstInsideWhen.kt")
public void testInlineStringConstInsideWhen() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/whenStringOptimization/inlineStringConstInsideWhen.kt");
doTest(fileName);
}
@TestMetadata("nonInlinedConst.kt")
public void testNonInlinedConst() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/whenStringOptimization/nonInlinedConst.kt");
@@ -21,8 +21,10 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.psi.KtConstantExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFile
@@ -44,8 +46,12 @@ class WrongPrimitiveLiteralFix(element: KtConstantExpression, type: KotlinType)
private val typeName = DescriptorUtils.getFqName(type.constructor.declarationDescriptor!!)
private val expectedTypeIsFloat = KotlinBuiltIns.isFloat(type)
private val expectedTypeIsDouble = KotlinBuiltIns.isDouble(type)
private val constValue
= ExpressionCodegen.getPrimitiveOrStringCompileTimeConstant(element, element.analyze(BodyResolveMode.PARTIAL))?.value as? Number
private val constValue = run {
val shouldInlineCosntVals = element.languageVersionSettings.supportsFeature(LanguageFeature.InlineConstVals)
ExpressionCodegen.getPrimitiveOrStringCompileTimeConstant(
element, element.analyze(BodyResolveMode.PARTIAL), shouldInlineCosntVals)?.value as? Number
}
private val fixedExpression = buildString {
if (expectedTypeIsFloat || expectedTypeIsDouble) {
@@ -13608,18 +13608,6 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("kt12200Const.kt")
public void testKt12200Const() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/kt12200Const.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("kt1398.kt")
public void testKt1398() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/properties/kt1398.kt");