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) {
|
public static int getReceiverIndex(@NotNull CodegenContext context, @NotNull CallableMemberDescriptor descriptor) {
|
||||||
OwnerKind kind = context.getContextKind();
|
OwnerKind kind = context.getContextKind();
|
||||||
//Trait always should have this descriptor
|
//Trait always should have this descriptor
|
||||||
|
|||||||
+37
-47
@@ -500,60 +500,50 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
|||||||
@Override
|
@Override
|
||||||
public void visitWhenExpression(@NotNull JetWhenExpression expression) {
|
public void visitWhenExpression(@NotNull JetWhenExpression expression) {
|
||||||
super.visitWhenExpression(expression);
|
super.visitWhenExpression(expression);
|
||||||
if (isWhenWithEnums(expression)) {
|
if (!isWhenWithEnums(expression)) return;
|
||||||
String currentClassName = getCurrentTopLevelClassOrPackagePartInternalName(expression.getContainingJetFile());
|
|
||||||
|
|
||||||
if (bindingContext.get(MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE, currentClassName) == null) {
|
String currentClassName = getCurrentTopLevelClassOrPackagePartInternalName(expression.getContainingJetFile());
|
||||||
bindingTrace.record(
|
|
||||||
MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE,
|
|
||||||
currentClassName,
|
|
||||||
new ArrayList<WhenByEnumsMapping>()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<WhenByEnumsMapping> mappings = bindingContext.get(MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE, currentClassName);
|
if (bindingContext.get(MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE, currentClassName) == null) {
|
||||||
assert mappings != null : "guaranteed by contract";
|
bindingTrace.record(MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE, currentClassName, new ArrayList<WhenByEnumsMapping>(1));
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
private boolean isWhenWithEnums(@NotNull JetWhenExpression expression) {
|
||||||
return WhenChecker.isWhenByEnum(expression, bindingContext) &&
|
return WhenChecker.isWhenByEnum(expression, bindingContext) &&
|
||||||
SwitchCodegenUtil.checkAllItemsAreConstantsSatisfying(
|
SwitchCodegenUtil.checkAllItemsAreConstantsSatisfying(
|
||||||
expression,
|
expression,
|
||||||
bindingContext,
|
bindingContext,
|
||||||
new Function1<CompileTimeConstant, Boolean>() {
|
new Function1<CompileTimeConstant, Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
public Boolean invoke(
|
public Boolean invoke(@NotNull CompileTimeConstant constant) {
|
||||||
@NotNull CompileTimeConstant constant
|
return constant instanceof EnumValue || constant instanceof NullValue;
|
||||||
) {
|
}
|
||||||
return constant instanceof EnumValue || constant instanceof NullValue;
|
}
|
||||||
}
|
);
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -52,20 +52,13 @@ public class EnumSwitchCodegen extends SwitchCodegen {
|
|||||||
|
|
||||||
v.swap();
|
v.swap();
|
||||||
|
|
||||||
v.invokevirtual(
|
Type enumType = codegen.getState().getTypeMapper().mapClass(mapping.getEnumClassDescriptor());
|
||||||
mapping.getEnumClassInternalName(),
|
v.invokevirtual(enumType.getInternalName(), "ordinal", Type.getMethodDescriptor(Type.INT_TYPE), false);
|
||||||
"ordinal",
|
|
||||||
Type.getMethodDescriptor(Type.INT_TYPE),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
v.aload(Type.INT_TYPE);
|
v.aload(Type.INT_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void processConstant(
|
protected void processConstant(@NotNull CompileTimeConstant constant, @NotNull Label entryLabel) {
|
||||||
@NotNull CompileTimeConstant constant,
|
|
||||||
@NotNull Label entryLabel
|
|
||||||
) {
|
|
||||||
assert constant instanceof EnumValue : "guaranteed by usage contract";
|
assert constant instanceof EnumValue : "guaranteed by usage contract";
|
||||||
putTransitionOnce(mapping.getIndexByEntry((EnumValue) constant), entryLabel);
|
putTransitionOnce(mapping.getIndexByEntry((EnumValue) constant), entryLabel);
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-40
@@ -18,11 +18,9 @@ package org.jetbrains.jet.codegen.when;
|
|||||||
|
|
||||||
import com.intellij.util.ArrayUtil;
|
import com.intellij.util.ArrayUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.codegen.AsmUtil;
|
|
||||||
import org.jetbrains.jet.codegen.ClassBuilder;
|
import org.jetbrains.jet.codegen.ClassBuilder;
|
||||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||||
import org.jetbrains.jet.lang.psi.JetFile;
|
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.constants.EnumValue;
|
||||||
import org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin;
|
import org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin;
|
||||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||||
@@ -43,16 +41,8 @@ public class MappingClassesForWhenByEnumCodegen {
|
|||||||
this.state = state;
|
this.state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void generate(
|
public void generate(@NotNull List<WhenByEnumsMapping> mappings, @NotNull Type mappingsClass, @NotNull JetFile srcFile) {
|
||||||
@NotNull List<WhenByEnumsMapping> mappings,
|
ClassBuilder cb = state.getFactory().newVisitor(JvmDeclarationOrigin.NO_ORIGIN, mappingsClass, srcFile);
|
||||||
@NotNull Type mappingsClass,
|
|
||||||
@NotNull JetFile srcFile
|
|
||||||
) {
|
|
||||||
ClassBuilder cb = state.getFactory().newVisitor(
|
|
||||||
JvmDeclarationOrigin.NO_ORIGIN,
|
|
||||||
mappingsClass,
|
|
||||||
srcFile
|
|
||||||
);
|
|
||||||
cb.defineClass(
|
cb.defineClass(
|
||||||
srcFile,
|
srcFile,
|
||||||
V1_6,
|
V1_6,
|
||||||
@@ -69,10 +59,7 @@ public class MappingClassesForWhenByEnumCodegen {
|
|||||||
cb.done();
|
cb.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void generateFields(
|
private static void generateFields(@NotNull ClassBuilder cb, @NotNull List<WhenByEnumsMapping> mappings) {
|
||||||
@NotNull ClassBuilder cb,
|
|
||||||
@NotNull List<WhenByEnumsMapping> mappings
|
|
||||||
) {
|
|
||||||
for (WhenByEnumsMapping mapping : mappings) {
|
for (WhenByEnumsMapping mapping : mappings) {
|
||||||
cb.newField(
|
cb.newField(
|
||||||
JvmDeclarationOrigin.NO_ORIGIN,
|
JvmDeclarationOrigin.NO_ORIGIN,
|
||||||
@@ -84,10 +71,7 @@ public class MappingClassesForWhenByEnumCodegen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void generateInitialization(
|
private void generateInitialization(@NotNull ClassBuilder cb, @NotNull List<WhenByEnumsMapping> mappings) {
|
||||||
@NotNull ClassBuilder cb,
|
|
||||||
@NotNull List<WhenByEnumsMapping> mappings
|
|
||||||
) {
|
|
||||||
MethodVisitor mv = cb.newMethod(
|
MethodVisitor mv = cb.newMethod(
|
||||||
JvmDeclarationOrigin.NO_ORIGIN,
|
JvmDeclarationOrigin.NO_ORIGIN,
|
||||||
ACC_STATIC | ACC_SYNTHETIC, "<clinit>", "()V", null, ArrayUtil.EMPTY_STRING_ARRAY
|
ACC_STATIC | ACC_SYNTHETIC, "<clinit>", "()V", null, ArrayUtil.EMPTY_STRING_ARRAY
|
||||||
@@ -107,40 +91,26 @@ public class MappingClassesForWhenByEnumCodegen {
|
|||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void generateInitializationForMapping(
|
private void generateInitializationForMapping(
|
||||||
@NotNull ClassBuilder cb,
|
@NotNull ClassBuilder cb,
|
||||||
@NotNull InstructionAdapter v,
|
@NotNull InstructionAdapter v,
|
||||||
@NotNull WhenByEnumsMapping mapping
|
@NotNull WhenByEnumsMapping mapping
|
||||||
) {
|
) {
|
||||||
v.invokestatic(
|
Type enumType = state.getTypeMapper().mapClass(mapping.getEnumClassDescriptor());
|
||||||
mapping.getEnumClassInternalName(), "values",
|
|
||||||
Type.getMethodDescriptor(
|
v.invokestatic(enumType.getInternalName(), "values", Type.getMethodDescriptor(Type.getType("[" + enumType.getDescriptor())), false);
|
||||||
AsmUtil.getArrayOf(mapping.getEnumClassInternalName())
|
|
||||||
),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
v.arraylength();
|
v.arraylength();
|
||||||
|
|
||||||
v.newarray(Type.INT_TYPE);
|
v.newarray(Type.INT_TYPE);
|
||||||
v.putstatic(cb.getThisName(), mapping.getFieldName(), MAPPINGS_FIELD_DESCRIPTOR);
|
v.putstatic(cb.getThisName(), mapping.getFieldName(), MAPPINGS_FIELD_DESCRIPTOR);
|
||||||
|
|
||||||
String enumClassDesc = Type.getObjectType(mapping.getEnumClassInternalName()).getDescriptor();
|
|
||||||
|
|
||||||
for (Map.Entry<EnumValue, Integer> item : mapping.enumValuesToIntMapping()) {
|
for (Map.Entry<EnumValue, Integer> item : mapping.enumValuesToIntMapping()) {
|
||||||
EnumValue enumEntry = item.getKey();
|
EnumValue enumEntry = item.getKey();
|
||||||
int mappedValue = item.getValue();
|
int mappedValue = item.getValue();
|
||||||
|
|
||||||
v.getstatic(cb.getThisName(), mapping.getFieldName(), MAPPINGS_FIELD_DESCRIPTOR);
|
v.getstatic(cb.getThisName(), mapping.getFieldName(), MAPPINGS_FIELD_DESCRIPTOR);
|
||||||
v.getstatic(
|
v.getstatic(enumType.getInternalName(), enumEntry.getValue().getName().asString(), enumType.getDescriptor());
|
||||||
mapping.getEnumClassInternalName(),
|
v.invokevirtual(enumType.getInternalName(), "ordinal", Type.getMethodDescriptor(Type.INT_TYPE), false);
|
||||||
enumEntry.getValue().getName().asString(),
|
|
||||||
enumClassDesc
|
|
||||||
);
|
|
||||||
v.invokevirtual(
|
|
||||||
mapping.getEnumClassInternalName(), "ordinal",
|
|
||||||
Type.getMethodDescriptor(Type.INT_TYPE),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
v.iconst(mappedValue);
|
v.iconst(mappedValue);
|
||||||
v.astore(Type.INT_TYPE);
|
v.astore(Type.INT_TYPE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.jet.codegen.when;
|
package org.jetbrains.jet.codegen.when;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||||
import org.jetbrains.jet.lang.resolve.constants.EnumValue;
|
import org.jetbrains.jet.lang.resolve.constants.EnumValue;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -27,13 +28,17 @@ public class WhenByEnumsMapping {
|
|||||||
private static final String MAPPINGS_CLASS_NAME_POSTFIX = "$WhenMappings";
|
private static final String MAPPINGS_CLASS_NAME_POSTFIX = "$WhenMappings";
|
||||||
|
|
||||||
private final Map<EnumValue, Integer> map = new HashMap<EnumValue, Integer>();
|
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 outerClassInternalNameForExpression;
|
||||||
private final String mappingsClassInternalName;
|
private final String mappingsClassInternalName;
|
||||||
private final int fieldNumber;
|
private final int fieldNumber;
|
||||||
|
|
||||||
public WhenByEnumsMapping(String enumClassInternalName, String outerClassInternalNameForExpression, int fieldNumber) {
|
public WhenByEnumsMapping(
|
||||||
this.enumClassInternalName = enumClassInternalName;
|
@NotNull ClassDescriptor enumClassDescriptor,
|
||||||
|
@NotNull String outerClassInternalNameForExpression,
|
||||||
|
int fieldNumber
|
||||||
|
) {
|
||||||
|
this.enumClassDescriptor = enumClassDescriptor;
|
||||||
this.outerClassInternalNameForExpression = outerClassInternalNameForExpression;
|
this.outerClassInternalNameForExpression = outerClassInternalNameForExpression;
|
||||||
this.mappingsClassInternalName = outerClassInternalNameForExpression + MAPPINGS_CLASS_NAME_POSTFIX;
|
this.mappingsClassInternalName = outerClassInternalNameForExpression + MAPPINGS_CLASS_NAME_POSTFIX;
|
||||||
this.fieldNumber = fieldNumber;
|
this.fieldNumber = fieldNumber;
|
||||||
@@ -45,7 +50,7 @@ public class WhenByEnumsMapping {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void putFirstTime(EnumValue value, int index) {
|
public void putFirstTime(@NotNull EnumValue value, int index) {
|
||||||
if (!map.containsKey(value)) {
|
if (!map.containsKey(value)) {
|
||||||
map.put(value, index);
|
map.put(value, index);
|
||||||
}
|
}
|
||||||
@@ -55,22 +60,27 @@ public class WhenByEnumsMapping {
|
|||||||
return map.size();
|
return map.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
public String getFieldName() {
|
public String getFieldName() {
|
||||||
return MAPPING_ARRAY_FIELD_PREFIX + fieldNumber;
|
return MAPPING_ARRAY_FIELD_PREFIX + fieldNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getEnumClassInternalName() {
|
@NotNull
|
||||||
return enumClassInternalName;
|
public ClassDescriptor getEnumClassDescriptor() {
|
||||||
|
return enumClassDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
public String getOuterClassInternalNameForExpression() {
|
public String getOuterClassInternalNameForExpression() {
|
||||||
return outerClassInternalNameForExpression;
|
return outerClassInternalNameForExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
public String getMappingsClassInternalName() {
|
public String getMappingsClassInternalName() {
|
||||||
return mappingsClassInternalName;
|
return mappingsClassInternalName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
public Iterable<Map.Entry<EnumValue, Integer>> enumValuesToIntMapping() {
|
public Iterable<Map.Entry<EnumValue, Integer>> enumValuesToIntMapping() {
|
||||||
return map.entrySet();
|
return map.entrySet();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user