Refactor when by enum switch codegen
Invoke getAsmType() later, not in the process of annotating the file
This commit is contained in:
@@ -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
|
||||
|
||||
+37
-47
@@ -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);
|
||||
}
|
||||
|
||||
+10
-40
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user