Refactor when by enum switch codegen

Invoke getAsmType() later, not in the process of annotating the file
This commit is contained in:
Alexander Udalov
2014-09-23 15:01:43 +04:00
parent d4a845da01
commit 232ab0b065
5 changed files with 66 additions and 108 deletions
@@ -803,11 +803,6 @@ public class AsmUtil {
}
}
@NotNull
public static Type getArrayOf(@NotNull String internalClassName) {
return Type.getType("[L" + internalClassName + ";");
}
public static int getReceiverIndex(@NotNull CodegenContext context, @NotNull CallableMemberDescriptor descriptor) {
OwnerKind kind = context.getContextKind();
//Trait always should have this descriptor
@@ -500,60 +500,50 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
@Override
public void visitWhenExpression(@NotNull JetWhenExpression expression) {
super.visitWhenExpression(expression);
if (isWhenWithEnums(expression)) {
String currentClassName = getCurrentTopLevelClassOrPackagePartInternalName(expression.getContainingJetFile());
if (!isWhenWithEnums(expression)) return;
if (bindingContext.get(MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE, currentClassName) == null) {
bindingTrace.record(
MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE,
currentClassName,
new ArrayList<WhenByEnumsMapping>()
);
}
String currentClassName = getCurrentTopLevelClassOrPackagePartInternalName(expression.getContainingJetFile());
List<WhenByEnumsMapping> mappings = bindingContext.get(MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE, currentClassName);
assert mappings != null : "guaranteed by contract";
int fieldNumber = mappings.size();
JetType type = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression.getSubjectExpression());
assert type != null : "should not be null in a valid when by enums";
ClassDescriptor classDescriptor = (ClassDescriptor) type.getConstructor().getDeclarationDescriptor();
assert classDescriptor != null : "because it's enum";
WhenByEnumsMapping mapping = new WhenByEnumsMapping(
CodegenBinding.getAsmType(bindingContext, classDescriptor).getInternalName(),
currentClassName,
fieldNumber
);
for (CompileTimeConstant constant : SwitchCodegenUtil.getAllConstants(expression, bindingContext)) {
if (constant instanceof NullValue) continue;
assert constant instanceof EnumValue : "expression in when should be EnumValue";
mapping.putFirstTime((EnumValue) constant, mapping.size() + 1);
}
mappings.add(mapping);
bindingTrace.record(MAPPING_FOR_WHEN_BY_ENUM, expression, mapping);
if (bindingContext.get(MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE, currentClassName) == null) {
bindingTrace.record(MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE, currentClassName, new ArrayList<WhenByEnumsMapping>(1));
}
List<WhenByEnumsMapping> mappings = bindingContext.get(MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE, currentClassName);
assert mappings != null : "guaranteed by contract";
int fieldNumber = mappings.size();
JetType type = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression.getSubjectExpression());
assert type != null : "should not be null in a valid when by enums";
ClassDescriptor classDescriptor = (ClassDescriptor) type.getConstructor().getDeclarationDescriptor();
assert classDescriptor != null : "because it's enum";
WhenByEnumsMapping mapping = new WhenByEnumsMapping(classDescriptor, currentClassName, fieldNumber);
for (CompileTimeConstant constant : SwitchCodegenUtil.getAllConstants(expression, bindingContext)) {
if (constant instanceof NullValue) continue;
assert constant instanceof EnumValue : "expression in when should be EnumValue";
mapping.putFirstTime((EnumValue) constant, mapping.size() + 1);
}
mappings.add(mapping);
bindingTrace.record(MAPPING_FOR_WHEN_BY_ENUM, expression, mapping);
}
private boolean isWhenWithEnums(@NotNull JetWhenExpression expression) {
return WhenChecker.isWhenByEnum(expression, bindingContext) &&
SwitchCodegenUtil.checkAllItemsAreConstantsSatisfying(
expression,
bindingContext,
new Function1<CompileTimeConstant, Boolean>() {
@Override
public Boolean invoke(
@NotNull CompileTimeConstant constant
) {
return constant instanceof EnumValue || constant instanceof NullValue;
}
}
);
SwitchCodegenUtil.checkAllItemsAreConstantsSatisfying(
expression,
bindingContext,
new Function1<CompileTimeConstant, Boolean>() {
@Override
public Boolean invoke(@NotNull CompileTimeConstant constant) {
return constant instanceof EnumValue || constant instanceof NullValue;
}
}
);
}
@NotNull
@@ -52,20 +52,13 @@ public class EnumSwitchCodegen extends SwitchCodegen {
v.swap();
v.invokevirtual(
mapping.getEnumClassInternalName(),
"ordinal",
Type.getMethodDescriptor(Type.INT_TYPE),
false
);
Type enumType = codegen.getState().getTypeMapper().mapClass(mapping.getEnumClassDescriptor());
v.invokevirtual(enumType.getInternalName(), "ordinal", Type.getMethodDescriptor(Type.INT_TYPE), false);
v.aload(Type.INT_TYPE);
}
@Override
protected void processConstant(
@NotNull CompileTimeConstant constant,
@NotNull Label entryLabel
) {
protected void processConstant(@NotNull CompileTimeConstant constant, @NotNull Label entryLabel) {
assert constant instanceof EnumValue : "guaranteed by usage contract";
putTransitionOnce(mapping.getIndexByEntry((EnumValue) constant), entryLabel);
}
@@ -18,11 +18,9 @@ package org.jetbrains.jet.codegen.when;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.codegen.AsmUtil;
import org.jetbrains.jet.codegen.ClassBuilder;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.constants.EnumValue;
import org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
@@ -43,16 +41,8 @@ public class MappingClassesForWhenByEnumCodegen {
this.state = state;
}
public void generate(
@NotNull List<WhenByEnumsMapping> mappings,
@NotNull Type mappingsClass,
@NotNull JetFile srcFile
) {
ClassBuilder cb = state.getFactory().newVisitor(
JvmDeclarationOrigin.NO_ORIGIN,
mappingsClass,
srcFile
);
public void generate(@NotNull List<WhenByEnumsMapping> mappings, @NotNull Type mappingsClass, @NotNull JetFile srcFile) {
ClassBuilder cb = state.getFactory().newVisitor(JvmDeclarationOrigin.NO_ORIGIN, mappingsClass, srcFile);
cb.defineClass(
srcFile,
V1_6,
@@ -69,10 +59,7 @@ public class MappingClassesForWhenByEnumCodegen {
cb.done();
}
private static void generateFields(
@NotNull ClassBuilder cb,
@NotNull List<WhenByEnumsMapping> mappings
) {
private static void generateFields(@NotNull ClassBuilder cb, @NotNull List<WhenByEnumsMapping> mappings) {
for (WhenByEnumsMapping mapping : mappings) {
cb.newField(
JvmDeclarationOrigin.NO_ORIGIN,
@@ -84,10 +71,7 @@ public class MappingClassesForWhenByEnumCodegen {
}
}
private static void generateInitialization(
@NotNull ClassBuilder cb,
@NotNull List<WhenByEnumsMapping> mappings
) {
private void generateInitialization(@NotNull ClassBuilder cb, @NotNull List<WhenByEnumsMapping> mappings) {
MethodVisitor mv = cb.newMethod(
JvmDeclarationOrigin.NO_ORIGIN,
ACC_STATIC | ACC_SYNTHETIC, "<clinit>", "()V", null, ArrayUtil.EMPTY_STRING_ARRAY
@@ -107,40 +91,26 @@ public class MappingClassesForWhenByEnumCodegen {
mv.visitEnd();
}
private static void generateInitializationForMapping(
private void generateInitializationForMapping(
@NotNull ClassBuilder cb,
@NotNull InstructionAdapter v,
@NotNull WhenByEnumsMapping mapping
) {
v.invokestatic(
mapping.getEnumClassInternalName(), "values",
Type.getMethodDescriptor(
AsmUtil.getArrayOf(mapping.getEnumClassInternalName())
),
false
);
Type enumType = state.getTypeMapper().mapClass(mapping.getEnumClassDescriptor());
v.invokestatic(enumType.getInternalName(), "values", Type.getMethodDescriptor(Type.getType("[" + enumType.getDescriptor())), false);
v.arraylength();
v.newarray(Type.INT_TYPE);
v.putstatic(cb.getThisName(), mapping.getFieldName(), MAPPINGS_FIELD_DESCRIPTOR);
String enumClassDesc = Type.getObjectType(mapping.getEnumClassInternalName()).getDescriptor();
for (Map.Entry<EnumValue, Integer> item : mapping.enumValuesToIntMapping()) {
EnumValue enumEntry = item.getKey();
int mappedValue = item.getValue();
v.getstatic(cb.getThisName(), mapping.getFieldName(), MAPPINGS_FIELD_DESCRIPTOR);
v.getstatic(
mapping.getEnumClassInternalName(),
enumEntry.getValue().getName().asString(),
enumClassDesc
);
v.invokevirtual(
mapping.getEnumClassInternalName(), "ordinal",
Type.getMethodDescriptor(Type.INT_TYPE),
false
);
v.getstatic(enumType.getInternalName(), enumEntry.getValue().getName().asString(), enumType.getDescriptor());
v.invokevirtual(enumType.getInternalName(), "ordinal", Type.getMethodDescriptor(Type.INT_TYPE), false);
v.iconst(mappedValue);
v.astore(Type.INT_TYPE);
}
@@ -17,6 +17,7 @@
package org.jetbrains.jet.codegen.when;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.resolve.constants.EnumValue;
import java.util.HashMap;
@@ -27,13 +28,17 @@ public class WhenByEnumsMapping {
private static final String MAPPINGS_CLASS_NAME_POSTFIX = "$WhenMappings";
private final Map<EnumValue, Integer> map = new HashMap<EnumValue, Integer>();
private final String enumClassInternalName;
private final ClassDescriptor enumClassDescriptor;
private final String outerClassInternalNameForExpression;
private final String mappingsClassInternalName;
private final int fieldNumber;
public WhenByEnumsMapping(String enumClassInternalName, String outerClassInternalNameForExpression, int fieldNumber) {
this.enumClassInternalName = enumClassInternalName;
public WhenByEnumsMapping(
@NotNull ClassDescriptor enumClassDescriptor,
@NotNull String outerClassInternalNameForExpression,
int fieldNumber
) {
this.enumClassDescriptor = enumClassDescriptor;
this.outerClassInternalNameForExpression = outerClassInternalNameForExpression;
this.mappingsClassInternalName = outerClassInternalNameForExpression + MAPPINGS_CLASS_NAME_POSTFIX;
this.fieldNumber = fieldNumber;
@@ -45,7 +50,7 @@ public class WhenByEnumsMapping {
return result;
}
public void putFirstTime(EnumValue value, int index) {
public void putFirstTime(@NotNull EnumValue value, int index) {
if (!map.containsKey(value)) {
map.put(value, index);
}
@@ -55,22 +60,27 @@ public class WhenByEnumsMapping {
return map.size();
}
@NotNull
public String getFieldName() {
return MAPPING_ARRAY_FIELD_PREFIX + fieldNumber;
}
public String getEnumClassInternalName() {
return enumClassInternalName;
@NotNull
public ClassDescriptor getEnumClassDescriptor() {
return enumClassDescriptor;
}
@NotNull
public String getOuterClassInternalNameForExpression() {
return outerClassInternalNameForExpression;
}
@NotNull
public String getMappingsClassInternalName() {
return mappingsClassInternalName;
}
@NotNull
public Iterable<Map.Entry<EnumValue, Integer>> enumValuesToIntMapping() {
return map.entrySet();
}