Refactoring: code duplication removed from constructor generators

This commit is contained in:
Mikhael Bogdanov
2013-03-13 12:05:07 +04:00
parent c8f3ecdce7
commit 001a27f802
4 changed files with 72 additions and 85 deletions
@@ -202,15 +202,6 @@ public class AsmUtil {
return NO_FLAG_PACKAGE_PRIVATE; return NO_FLAG_PACKAGE_PRIVATE;
} }
public static int getModalityAccessFlag(@NotNull MemberDescriptor descriptor) {
switch (descriptor.getModality()) {
case ABSTRACT: return ACC_ABSTRACT;
case FINAL: return ACC_FINAL;
case OPEN: return 0;
default: throw new UnsupportedOperationException("Unknown modality: " + descriptor.getModality());
}
}
public static int getDeprecatedAccessFlag(@NotNull MemberDescriptor descriptor) { public static int getDeprecatedAccessFlag(@NotNull MemberDescriptor descriptor) {
if (descriptor instanceof PropertyAccessorDescriptor) { if (descriptor instanceof PropertyAccessorDescriptor) {
return KotlinBuiltIns.getInstance().isDeprecated(descriptor) return KotlinBuiltIns.getInstance().isDeprecated(descriptor)
@@ -325,6 +316,7 @@ public class AsmUtil {
} }
public static void genInitSingletonField(FieldInfo info, InstructionAdapter iv) { public static void genInitSingletonField(FieldInfo info, InstructionAdapter iv) {
assert info.isStatic();
genInitSingletonField(info.getOwnerType(), info.getFieldName(), info.getFieldType(), iv); genInitSingletonField(info.getOwnerType(), info.getFieldName(), info.getFieldType(), iv);
} }
@@ -335,6 +327,16 @@ public class AsmUtil {
iv.putstatic(fieldOwnerType.getInternalName(), fieldName, fieldAsmType.getDescriptor()); iv.putstatic(fieldOwnerType.getInternalName(), fieldName, fieldAsmType.getDescriptor());
} }
public static int genAssignInstanceFieldFromParam(FieldInfo info, int index, InstructionAdapter iv) {
assert !info.isStatic();
Type fieldType = info.getFieldType();
iv.load(0, info.getOwnerType());//this
iv.load(index, fieldType); //param
iv.visitFieldInsn(PUTFIELD, info.getOwnerInternalName(), info.getFieldName(), fieldType.getDescriptor());
index += fieldType.getSize();
return index;
}
public static void genStringBuilderConstructor(InstructionAdapter v) { public static void genStringBuilderConstructor(InstructionAdapter v) {
v.visitTypeInsn(NEW, "java/lang/StringBuilder"); v.visitTypeInsn(NEW, "java/lang/StringBuilder");
v.dup(); v.dup();
@@ -16,8 +16,9 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import com.intellij.openapi.util.Pair; import com.google.common.collect.Lists;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type; import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.InstructionAdapter;
@@ -29,6 +30,7 @@ import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.signature.JvmMethodSignature; import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.GenerationStateAware; import org.jetbrains.jet.codegen.state.GenerationStateAware;
import org.jetbrains.jet.codegen.state.JetTypeMapper;
import org.jetbrains.jet.codegen.state.JetTypeMapperMode; import org.jetbrains.jet.codegen.state.JetTypeMapperMode;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody; import org.jetbrains.jet.lang.psi.JetDeclarationWithBody;
@@ -40,7 +42,6 @@ import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.asm4.Opcodes.*;
@@ -197,10 +198,11 @@ public class ClosureCodegen extends GenerationStateAware {
ClassBuilder cv, ClassBuilder cv,
CalculatedClosure closure CalculatedClosure closure
) { ) {
ArrayList<Pair<String, Type>> args = new ArrayList<Pair<String, Type>>();
calculateConstructorParameters(args, state, closure);
Type[] argTypes = nameAnTypeListToTypeArray(args); List<FieldInfo> args = calculateConstructorParameters(typeMapper, bindingContext, state, closure,
Type.getObjectType(name.getInternalName()));
Type[] argTypes = fieldListToTypeArray(args);
Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes); Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes);
MethodVisitor mv = cv.newMethod(fun, ACC_PUBLIC, "<init>", constructor.getDescriptor(), null, new String[0]); MethodVisitor mv = cv.newMethod(fun, ACC_PUBLIC, "<init>", constructor.getDescriptor(), null, new String[0]);
@@ -215,13 +217,8 @@ public class ClosureCodegen extends GenerationStateAware {
iv.invokespecial(funClass.getInternalName(), "<init>", "()V"); iv.invokespecial(funClass.getInternalName(), "<init>", "()V");
int k = 1; int k = 1;
for (int i = 0; i != argTypes.length; ++i) { for (FieldInfo fieldInfo : args) {
StackValue.local(0, OBJECT_TYPE).put(OBJECT_TYPE, iv); k = AsmUtil.genAssignInstanceFieldFromParam(fieldInfo, k, iv);
Pair<String, Type> nameAndType = args.get(i);
Type type = nameAndType.second;
StackValue.local(k, type).put(type, iv);
k += type.getSize();
StackValue.field(type, name, nameAndType.first, false).store(type, iv);
} }
iv.visitInsn(RETURN); iv.visitInsn(RETURN);
@@ -231,19 +228,24 @@ public class ClosureCodegen extends GenerationStateAware {
return constructor; return constructor;
} }
private void calculateConstructorParameters( @NotNull
List<Pair<String, Type>> args, public static List<FieldInfo> calculateConstructorParameters(
@NotNull JetTypeMapper typeMapper,
@NotNull BindingContext bindingContext,
GenerationState state, GenerationState state,
CalculatedClosure closure CalculatedClosure closure,
Type ownerType
) { ) {
List<FieldInfo> args = Lists.newArrayList();
ClassDescriptor captureThis = closure.getCaptureThis(); ClassDescriptor captureThis = closure.getCaptureThis();
if (captureThis != null) { if (captureThis != null) {
Type type = typeMapper.mapType(captureThis); Type type = typeMapper.mapType(captureThis);
args.add(new Pair<String, Type>(CAPTURED_THIS_FIELD, type)); args.add(FieldInfo.createForHiddenField(ownerType, type, CAPTURED_THIS_FIELD));
} }
ClassifierDescriptor captureReceiver = closure.getCaptureReceiver(); ClassifierDescriptor captureReceiver = closure.getCaptureReceiver();
if (captureReceiver != null) { if (captureReceiver != null) {
args.add(new Pair<String, Type>(CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiver))); args.add(FieldInfo.createForHiddenField(ownerType, typeMapper.mapType(captureReceiver), CAPTURED_RECEIVER_FIELD));
} }
for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) { for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) {
@@ -253,7 +255,7 @@ public class ClosureCodegen extends GenerationStateAware {
Type type = sharedVarType != null Type type = sharedVarType != null
? sharedVarType ? sharedVarType
: typeMapper.mapType((VariableDescriptor) descriptor); : typeMapper.mapType((VariableDescriptor) descriptor);
args.add(new Pair<String, Type>("$" + descriptor.getName().getName(), type)); args.add(FieldInfo.createForHiddenField(ownerType, type, "$" + descriptor.getName().getName()));
} }
else if (isLocalNamedFun(state.getBindingContext(), descriptor)) { else if (isLocalNamedFun(state.getBindingContext(), descriptor)) {
Type type = Type type =
@@ -261,18 +263,19 @@ public class ClosureCodegen extends GenerationStateAware {
(JetElement) BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor)) (JetElement) BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor))
.getAsmType(); .getAsmType();
args.add(new Pair<String, Type>("$" + descriptor.getName().getName(), type)); args.add(FieldInfo.createForHiddenField(ownerType, type, "$" + descriptor.getName().getName()));
} }
else if (descriptor instanceof FunctionDescriptor) { else if (descriptor instanceof FunctionDescriptor) {
assert captureReceiver != null; assert captureReceiver != null;
} }
} }
return args;
} }
private static Type[] nameAnTypeListToTypeArray(List<Pair<String, Type>> args) { private static Type[] fieldListToTypeArray(List<FieldInfo> args) {
Type[] argTypes = new Type[args.size()]; Type[] argTypes = new Type[args.size()];
for (int i = 0; i != argTypes.length; ++i) { for (int i = 0; i != argTypes.length; ++i) {
argTypes[i] = args.get(i).second; argTypes[i] = args.get(i).getFieldType();
} }
return argTypes; return argTypes;
} }
@@ -26,16 +26,44 @@ import org.jetbrains.jet.lang.resolve.java.JvmAbi;
public class FieldInfo { public class FieldInfo {
@NotNull
public static FieldInfo createForSingleton(@NotNull ClassDescriptor fieldClassDescriptor, @NotNull JetTypeMapper typeMapper) {
ClassKind kind = fieldClassDescriptor.getKind();
if (kind != ClassKind.OBJECT && kind != ClassKind.CLASS_OBJECT && kind != ClassKind.ENUM_ENTRY) {
throw new UnsupportedOperationException();
}
Type fieldType = typeMapper.mapType(fieldClassDescriptor.getDefaultType());
ClassDescriptor ownerDescriptor = kind == ClassKind.OBJECT
? fieldClassDescriptor: DescriptorUtils.getParentOfType(fieldClassDescriptor, ClassDescriptor.class);
assert ownerDescriptor != null;
Type ownerType = typeMapper.mapType(ownerDescriptor.getDefaultType());
String fieldName = kind == ClassKind.ENUM_ENTRY
? fieldClassDescriptor.getName().getName()
: fieldClassDescriptor.getKind() == ClassKind.CLASS_OBJECT ? JvmAbi.CLASS_OBJECT_FIELD : JvmAbi.INSTANCE_FIELD;
return new FieldInfo(ownerType, fieldType, fieldName, true);
}
public static FieldInfo createForHiddenField(@NotNull Type owner, Type fieldType, String fieldName) {
return new FieldInfo(owner, fieldType, fieldName, false);
}
private final Type fieldType; private final Type fieldType;
private final Type ownerType; private final Type ownerType;
private final String fieldName; private final String fieldName;
private FieldInfo(@NotNull Type ownerType, @NotNull Type fieldType, @NotNull String fieldName) { private final boolean isStatic;
private FieldInfo(@NotNull Type ownerType, @NotNull Type fieldType, @NotNull String fieldName, @NotNull boolean isStatic) {
this.ownerType = ownerType; this.ownerType = ownerType;
this.fieldType = fieldType; this.fieldType = fieldType;
this.fieldName = fieldName; this.fieldName = fieldName;
this.isStatic = isStatic;
} }
@NotNull @NotNull
@@ -59,23 +87,7 @@ public class FieldInfo {
} }
@NotNull @NotNull
public static FieldInfo createForSingleton(@NotNull ClassDescriptor fieldClassDescriptor, @NotNull JetTypeMapper typeMapper) { public boolean isStatic() {
ClassKind kind = fieldClassDescriptor.getKind(); return isStatic;
if (kind != ClassKind.OBJECT && kind != ClassKind.CLASS_OBJECT && kind != ClassKind.ENUM_ENTRY) {
throw new UnsupportedOperationException();
}
Type fieldType = typeMapper.mapType(fieldClassDescriptor.getDefaultType());
ClassDescriptor ownerDescriptor = kind == ClassKind.OBJECT
? fieldClassDescriptor: DescriptorUtils.getParentOfType(fieldClassDescriptor, ClassDescriptor.class);
assert ownerDescriptor != null;
Type ownerType = typeMapper.mapType(ownerDescriptor.getDefaultType());
String fieldName = kind == ClassKind.ENUM_ENTRY
? fieldClassDescriptor.getName().getName()
: fieldClassDescriptor.getKind() == ClassKind.CLASS_OBJECT ? JvmAbi.CLASS_OBJECT_FIELD : JvmAbi.INSTANCE_FIELD;
return new FieldInfo(ownerType, fieldType, fieldName);
} }
} }
@@ -955,7 +955,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
ClassDescriptor fieldTypeDescriptor = hasClassObject ? descriptor.getClassObjectDescriptor() : descriptor; ClassDescriptor fieldTypeDescriptor = hasClassObject ? descriptor.getClassObjectDescriptor() : descriptor;
assert fieldTypeDescriptor != null; assert fieldTypeDescriptor != null;
final FieldInfo info = FieldInfo.createForSingleton(fieldTypeDescriptor, typeMapper); final FieldInfo info = FieldInfo.createForSingleton(fieldTypeDescriptor, typeMapper);
JetClassOrObject original = hasClassObject ? ((JetClass)myClass).getClassObject().getObjectDeclaration() : myClass; JetClassOrObject original = hasClassObject ? ((JetClass) myClass).getClassObject().getObjectDeclaration() : myClass;
v.newField(original, ACC_PUBLIC | ACC_STATIC | ACC_FINAL, info.getFieldName(), info.getFieldType().getDescriptor(), null, null); v.newField(original, ACC_PUBLIC | ACC_STATIC | ACC_FINAL, info.getFieldName(), info.getFieldType().getDescriptor(), null, null);
@@ -1012,8 +1012,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
return; return;
} }
generatePrimaryConstructorImpl(constructorDescriptor, constructorContext, constructorMethod, callableMethod, hasCapturedThis, generatePrimaryConstructorImpl(constructorDescriptor, constructorContext, constructorMethod, callableMethod, closure, mv);
closure, mv);
} }
FunctionCodegen.generateConstructorWithoutParametersIfNeeded(state, callableMethod, constructorDescriptor, v); FunctionCodegen.generateConstructorWithoutParametersIfNeeded(state, callableMethod, constructorDescriptor, v);
@@ -1024,7 +1023,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
ConstructorContext constructorContext, ConstructorContext constructorContext,
JvmMethodSignature constructorMethod, JvmMethodSignature constructorMethod,
CallableMethod callableMethod, CallableMethod callableMethod,
boolean hasCapturedThis,
MutableClosure closure, MutableClosure closure,
MethodVisitor mv MethodVisitor mv
) { ) {
@@ -1051,39 +1049,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
generateDelegatorToConstructorCall(iv, codegen, constructorDescriptor, frameMap); generateDelegatorToConstructorCall(iv, codegen, constructorDescriptor, frameMap);
} }
if (hasCapturedThis) {
Type type = typeMapper
.mapType(enclosingClassDescriptor(bindingContext, descriptor));
String interfaceDesc = type.getDescriptor();
iv.load(0, classAsmType);
iv.load(frameMap.getOuterThisIndex(), type);
iv.putfield(classname.getInternalName(), CAPTURED_THIS_FIELD, interfaceDesc);
}
if (closure != null) { if (closure != null) {
int k = hasCapturedThis ? 2 : 1; List<FieldInfo> argsFromClosure = ClosureCodegen.calculateConstructorParameters(typeMapper, bindingContext, state, closure, classAsmType);
String internalName = typeMapper.mapType(descriptor).getInternalName(); int k = 1;
ClassifierDescriptor captureReceiver = closure.getCaptureReceiver(); for (FieldInfo info : argsFromClosure) {
if (captureReceiver != null) { k = AsmUtil.genAssignInstanceFieldFromParam(info, k, iv);
iv.load(0, OBJECT_TYPE);
Type asmType = typeMapper.mapType(captureReceiver.getDefaultType(), JetTypeMapperMode.IMPL);
iv.load(k, asmType);
iv.putfield(internalName, CAPTURED_RECEIVER_FIELD, asmType.getDescriptor());
k += asmType.getSize();
}
for (DeclarationDescriptor varDescr : closure.getCaptureVariables().keySet()) {
if (varDescr instanceof VariableDescriptor && !(varDescr instanceof PropertyDescriptor)) {
Type sharedVarType = typeMapper.getSharedVarType(varDescr);
if (sharedVarType == null) {
sharedVarType = typeMapper.mapType((VariableDescriptor) varDescr);
}
iv.load(0, OBJECT_TYPE);
iv.load(k, StackValue.refType(sharedVarType));
k += StackValue.refType(sharedVarType).getSize();
iv.putfield(internalName,
"$" + varDescr.getName(), sharedVarType.getDescriptor());
}
} }
} }