Refactoring: code duplication removed from accessor generators

This commit is contained in:
Mikhael Bogdanov
2013-03-13 12:03:42 +04:00
parent 86f5114b7d
commit d9fd04dd43
32 changed files with 1026 additions and 521 deletions
@@ -37,9 +37,7 @@ 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.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody;
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
import org.jetbrains.jet.lang.psi.JetNamedFunction;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
@@ -81,13 +79,16 @@ public class FunctionCodegen extends GenerationStateAware {
generateMethod(f, method, true, null, functionDescriptor);
}
public void generateMethod(
JetDeclarationWithBody fun,
JvmMethodSignature jvmSignature,
@NotNull PsiElement declaration,
@NotNull JvmMethodSignature jvmSignature,
boolean needJetAnnotations,
@Nullable String propertyTypeSignature,
FunctionDescriptor functionDescriptor
@NotNull FunctionDescriptor functionDescriptor
) {
assert declaration instanceof JetDeclarationWithBody || declaration instanceof JetProperty || declaration instanceof JetParameter;
checkMustGenerateCode(functionDescriptor);
OwnerKind kind = owner.getContextKind();
@@ -96,9 +97,11 @@ public class FunctionCodegen extends GenerationStateAware {
needJetAnnotations = false;
}
boolean hasBodyExpression = hasBodyExpression(declaration);
MethodContext context = owner.intoFunction(functionDescriptor);
if (kind != OwnerKind.TRAIT_IMPL || fun.getBodyExpression() != null) {
generateMethodHeaderAndBody(fun, jvmSignature, needJetAnnotations, propertyTypeSignature, functionDescriptor, context);
if (kind != OwnerKind.TRAIT_IMPL || hasBodyExpression) {
generateMethodHeaderAndBody(declaration, jvmSignature, needJetAnnotations, propertyTypeSignature, functionDescriptor, context);
if (state.getClassBuilderMode() == ClassBuilderMode.FULL && !isAbstract(functionDescriptor, kind)) {
generateBridgeIfNeeded(owner, state, v, jvmSignature.getAsmMethod(), functionDescriptor);
@@ -109,7 +112,7 @@ public class FunctionCodegen extends GenerationStateAware {
}
private void generateMethodHeaderAndBody(
@NotNull JetDeclarationWithBody fun,
@NotNull PsiElement declaration,
@NotNull JvmMethodSignature jvmSignature,
boolean needJetAnnotations,
@Nullable String propertyTypeSignature,
@@ -119,7 +122,7 @@ public class FunctionCodegen extends GenerationStateAware {
OwnerKind kind = context.getContextKind();
Method asmMethod = jvmSignature.getAsmMethod();
MethodVisitor mv = v.newMethod(fun,
MethodVisitor mv = v.newMethod(declaration,
getMethodAsmFlags(functionDescriptor, kind),
asmMethod.getName(),
asmMethod.getDescriptor(),
@@ -142,14 +145,14 @@ public class FunctionCodegen extends GenerationStateAware {
LocalVariablesInfo localVariablesInfo = generateLocalVariablesInfo(functionDescriptor);
MethodBounds methodBounds = generateMethodBody(mv, fun, functionDescriptor, context, asmMethod, localVariablesInfo);
MethodBounds methodBounds = generateMethodBody(mv, declaration, functionDescriptor, context, asmMethod, localVariablesInfo);
Type thisType;
ReceiverParameterDescriptor expectedThisObject = functionDescriptor.getExpectedThisObject();
if (expectedThisObject != null) {
thisType = typeMapper.mapType(expectedThisObject.getType());
}
else if (fun instanceof JetFunctionLiteralExpression || isLocalFun(bindingContext, functionDescriptor)) {
else if (declaration instanceof JetFunctionLiteralExpression || isLocalFun(bindingContext, functionDescriptor)) {
thisType = typeMapper.mapType(context.getThisDescriptor());
}
else {
@@ -158,13 +161,13 @@ public class FunctionCodegen extends GenerationStateAware {
generateLocalVariableTable(typeMapper, mv, functionDescriptor, thisType, localVariablesInfo, methodBounds);
endVisit(mv, null, fun);
endVisit(mv, null, declaration);
}
@NotNull
private MethodBounds generateMethodBody(
@NotNull MethodVisitor mv,
@NotNull JetDeclarationWithBody fun,
@NotNull PsiElement funOrProperty,
@NotNull FunctionDescriptor functionDescriptor,
@NotNull MethodContext context,
@NotNull Method asmMethod,
@@ -201,10 +204,23 @@ public class FunctionCodegen extends GenerationStateAware {
genNotNullAssertionsForParameters(new InstructionAdapter(mv), state, functionDescriptor, frameMap);
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, asmMethod.getReturnType(), context, state);
codegen.returnExpression(fun.getBodyExpression());
boolean hasBodyExpression = hasBodyExpression(funOrProperty);
if (hasBodyExpression) {
JetDeclarationWithBody fun = (JetDeclarationWithBody)funOrProperty;
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, asmMethod.getReturnType(), context, state);
codegen.returnExpression(fun.getBodyExpression());
localVariablesInfo.names.addAll(codegen.getLocalVariableNamesForExpression());
localVariablesInfo.names.addAll(codegen.getLocalVariableNamesForExpression());
} else {
///generate default accessor
assert functionDescriptor instanceof PropertyAccessorDescriptor;
PropertyCodegen.generateDefaultAccessor(
(PropertyAccessorDescriptor) functionDescriptor,
new InstructionAdapter(mv),
kind,
typeMapper,
context);
}
}
Label methodEnd = new Label();
@@ -213,6 +229,12 @@ public class FunctionCodegen extends GenerationStateAware {
return new MethodBounds(methodBegin, methodEnd);
}
private static boolean hasBodyExpression(PsiElement funOrProperty) {
return (funOrProperty instanceof JetDeclarationWithBody
&& ((JetDeclarationWithBody)funOrProperty).getBodyExpression() != null);
}
public static class MethodBounds {
@NotNull private final Label begin;
@@ -24,14 +24,14 @@ import org.jetbrains.asm4.MethodVisitor;
import org.jetbrains.asm4.Type;
import org.jetbrains.asm4.commons.InstructionAdapter;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
import org.jetbrains.jet.codegen.signature.JvmPropertyAccessorSignature;
import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter;
import org.jetbrains.jet.codegen.state.GenerationStateAware;
import org.jetbrains.jet.codegen.state.JetTypeMapper;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.DescriptorResolver;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
@@ -40,9 +40,8 @@ import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.AsmUtil.*;
import static org.jetbrains.jet.codegen.AsmUtil.getDeprecatedAccessFlag;
import static org.jetbrains.jet.codegen.CodegenUtil.*;
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isExternallyAccessible;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
@@ -72,16 +71,15 @@ public class PropertyCodegen extends GenerationStateAware {
if (kind != OwnerKind.TRAIT_IMPL && !(kind instanceof OwnerKind.StaticDelegateKind)) {
generateBackingField(p, propertyDescriptor);
}
generateGetter(p, propertyDescriptor);
generateSetter(p, propertyDescriptor);
generateGetter(p, propertyDescriptor, p.getGetter());
generateSetter(p, propertyDescriptor, p.getSetter());
}
public void generatePrimaryConstructorProperty(JetParameter p, PropertyDescriptor descriptor) {
generateBackingField(p, descriptor);
int accessFlags = getVisibilityAccessFlag(descriptor) | getModalityAccessFlag(descriptor) | getDeprecatedAccessFlag(descriptor);
generateDefaultGetter(descriptor, accessFlags, p);
generateGetter(p, descriptor, null);
if (descriptor.isVar()) {
generateDefaultSetter(descriptor, accessFlags, p);
generateSetter(p, descriptor, null);
}
}
@@ -121,107 +119,73 @@ public class PropertyCodegen extends GenerationStateAware {
}
}
private void generateGetter(JetProperty p, PropertyDescriptor propertyDescriptor) {
JetPropertyAccessor getter = p.getGetter();
PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter();
if (getter != null && getter.getBodyExpression() != null) {
private void generateGetter(JetNamedDeclaration p, PropertyDescriptor propertyDescriptor, JetPropertyAccessor getter) {
if (getter != null && getter.getBodyExpression() != null || isExternallyAccessible(propertyDescriptor)) {
JvmPropertyAccessorSignature signature = typeMapper.mapGetterSignature(propertyDescriptor, kind);
functionCodegen.generateMethod(getter, signature.getJvmMethodSignature(), true, signature.getPropertyTypeKotlinSignature(),
PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter();
getterDescriptor = getterDescriptor != null ? getterDescriptor : DescriptorResolver.createDefaultGetter(propertyDescriptor);
functionCodegen.generateMethod(getter != null ? getter : p,
signature.getJvmMethodSignature(),
true,
signature.getPropertyTypeKotlinSignature(),
getterDescriptor);
}
else if (isExternallyAccessible(propertyDescriptor)) {
int flags = getVisibilityAccessFlag(propertyDescriptor);
flags |= getModalityAccessFlag(propertyDescriptor);
flags |= getterDescriptor == null ? getDeprecatedAccessFlag(propertyDescriptor): getDeprecatedAccessFlag(getterDescriptor);
generateDefaultGetter(propertyDescriptor, flags, p);
}
}
private void generateSetter(JetProperty p, PropertyDescriptor propertyDescriptor) {
JetPropertyAccessor setter = p.getSetter();
if (setter != null && setter.getBodyExpression() != null) {
private void generateSetter(JetNamedDeclaration p, PropertyDescriptor propertyDescriptor, JetPropertyAccessor setter) {
if (setter != null && setter.getBodyExpression() != null
|| isExternallyAccessible(propertyDescriptor) && propertyDescriptor.isVar()) {
JvmPropertyAccessorSignature signature = typeMapper.mapSetterSignature(propertyDescriptor, kind);
functionCodegen.generateMethod(setter, signature.getJvmMethodSignature(), true, signature.getPropertyTypeKotlinSignature(),
propertyDescriptor.getSetter());
}
else if (isExternallyAccessible(propertyDescriptor) && propertyDescriptor.isVar()) {
PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter();
int flags = getModalityAccessFlag(propertyDescriptor);
if (setterDescriptor == null) {
flags |= getVisibilityAccessFlag(propertyDescriptor);
flags |= getDeprecatedAccessFlag(propertyDescriptor);
}
else {
flags |= getVisibilityAccessFlag(setterDescriptor);
flags |= getDeprecatedAccessFlag(setterDescriptor);
}
generateDefaultSetter(propertyDescriptor, flags, p);
setterDescriptor = setterDescriptor != null ? setterDescriptor : DescriptorResolver.createDefaultSetter(propertyDescriptor);
functionCodegen.generateMethod(setter != null ? setter : p,
signature.getJvmMethodSignature(),
true,
signature.getPropertyTypeKotlinSignature(),
setterDescriptor);
}
}
private void generateDefaultGetter(PropertyDescriptor propertyDescriptor, int flags, PsiElement origin) {
checkMustGenerateCode(propertyDescriptor);
if (kind == OwnerKind.TRAIT_IMPL) {
return;
}
public static void generateDefaultAccessor(
@NotNull PropertyAccessorDescriptor accessorDescriptor,
@NotNull InstructionAdapter iv,
@NotNull OwnerKind kind,
@NotNull JetTypeMapper typeMapper,
@NotNull CodegenContext context) {
if (kind == OwnerKind.NAMESPACE || kind instanceof OwnerKind.StaticDelegateKind) {
flags |= ACC_STATIC;
}
PsiElement psiElement = descriptorToDeclaration(bindingContext, propertyDescriptor.getContainingDeclaration());
boolean isTrait = psiElement instanceof JetClass && ((JetClass) psiElement).isTrait();
if (isTrait) {
flags |= ACC_ABSTRACT;
}
JvmPropertyAccessorSignature signature = typeMapper.mapGetterSignature(propertyDescriptor, kind);
JvmMethodSignature jvmMethodSignature = signature.getJvmMethodSignature();
String descriptor = jvmMethodSignature.getAsmMethod().getDescriptor();
String getterName = getterName(propertyDescriptor.getName());
MethodVisitor mv = v.newMethod(origin, flags, getterName, descriptor, jvmMethodSignature.getGenericsSignature(), null);
PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
generateJetPropertyAnnotation(mv, signature.getPropertyTypeKotlinSignature(),
jvmMethodSignature.getKotlinTypeParameter(), propertyDescriptor,
getter == null
? propertyDescriptor.getVisibility()
: getter.getVisibility());
if (getter != null) {
//noinspection ConstantConditions
assert !getter.hasBody();
AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(getter);
}
if (state.getClassBuilderMode() != ClassBuilderMode.SIGNATURES && !isTrait) {
if (propertyDescriptor.getModality() != Modality.ABSTRACT) {
mv.visitCode();
if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
genStubThrow(mv);
}
else if (kind instanceof OwnerKind.StaticDelegateKind) {
FunctionCodegen.generateStaticDelegateMethodBody(mv, jvmMethodSignature.getAsmMethod(), (OwnerKind.StaticDelegateKind) kind);
}
else {
InstructionAdapter iv = new InstructionAdapter(mv);
if (kind != OwnerKind.NAMESPACE) {
iv.load(0, OBJECT_TYPE);
}
Type type = typeMapper.mapType(propertyDescriptor);
iv.visitFieldInsn(
kind == OwnerKind.NAMESPACE ? GETSTATIC : GETFIELD,
typeMapper.getOwner(propertyDescriptor, kind, isCallInsideSameModuleAsDeclared(propertyDescriptor, context)).getInternalName(),
propertyDescriptor.getName().getName(),
type.getDescriptor());
iv.areturn(type);
}
PropertyDescriptor propertyDescriptor = accessorDescriptor.getCorrespondingProperty();
final Type type = typeMapper.mapType(propertyDescriptor);
if (accessorDescriptor instanceof PropertyGetterDescriptor) {
if (kind != OwnerKind.NAMESPACE) {
iv.load(0, OBJECT_TYPE);
}
}
FunctionCodegen.endVisit(mv, "getter", origin);
iv.visitFieldInsn(
kind == OwnerKind.NAMESPACE ? GETSTATIC : GETFIELD,
typeMapper.getOwner(propertyDescriptor, kind, isCallInsideSameModuleAsDeclared(propertyDescriptor, context)).getInternalName(),
propertyDescriptor.getName().getName(),
type.getDescriptor());
iv.areturn(type);
} else if (accessorDescriptor instanceof PropertySetterDescriptor) {
int paramCode = 0;
if (kind != OwnerKind.NAMESPACE) {
iv.load(0, OBJECT_TYPE);
paramCode = 1;
}
ReceiverParameterDescriptor receiverParameter = propertyDescriptor.getReceiverParameter();
if (receiverParameter != null) {
paramCode += typeMapper.mapType(receiverParameter.getType()).getSize();
}
iv.load(paramCode, type);
iv.visitFieldInsn(kind == OwnerKind.NAMESPACE ? PUTSTATIC : PUTFIELD,
typeMapper.getOwner(propertyDescriptor, kind, isCallInsideSameModuleAsDeclared(propertyDescriptor, context)).getInternalName(),
propertyDescriptor.getName().getName(),
type.getDescriptor());
FunctionCodegen.generateBridgeIfNeeded(context, state, v, jvmMethodSignature.getAsmMethod(), getter);
iv.visitInsn(RETURN);
} else {
assert false;
}
}
public static void generateJetPropertyAnnotation(
@@ -242,73 +206,6 @@ public class PropertyCodegen extends GenerationStateAware {
aw.visitEnd();
}
private void generateDefaultSetter(PropertyDescriptor propertyDescriptor, int flags, PsiElement origin) {
checkMustGenerateCode(propertyDescriptor);
if (kind == OwnerKind.TRAIT_IMPL) {
return;
}
if (kind == OwnerKind.NAMESPACE || kind instanceof OwnerKind.StaticDelegateKind) {
flags |= ACC_STATIC;
}
PsiElement psiElement = descriptorToDeclaration(bindingContext, propertyDescriptor.getContainingDeclaration());
boolean isTrait = psiElement instanceof JetClass && ((JetClass) psiElement).isTrait();
if (isTrait) {
flags |= ACC_ABSTRACT;
}
JvmPropertyAccessorSignature signature = typeMapper.mapSetterSignature(propertyDescriptor, kind);
assert true;
JvmMethodSignature jvmMethodSignature = signature.getJvmMethodSignature();
String descriptor = jvmMethodSignature.getAsmMethod().getDescriptor();
MethodVisitor mv = v.newMethod(origin, flags, setterName(propertyDescriptor.getName()), descriptor, jvmMethodSignature.getGenericsSignature(), null);
PropertySetterDescriptor setter = propertyDescriptor.getSetter();
assert setter != null;
generateJetPropertyAnnotation(mv, signature.getPropertyTypeKotlinSignature(),
jvmMethodSignature.getKotlinTypeParameter(), propertyDescriptor,
setter.getVisibility());
assert !setter.hasBody();
AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(setter);
if (state.getClassBuilderMode() != ClassBuilderMode.SIGNATURES && (!isTrait)) {
if (propertyDescriptor.getModality() != Modality.ABSTRACT) {
mv.visitCode();
if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
genStubThrow(mv);
}
else if (kind instanceof OwnerKind.StaticDelegateKind) {
FunctionCodegen.generateStaticDelegateMethodBody(mv, jvmMethodSignature.getAsmMethod(), (OwnerKind.StaticDelegateKind) kind);
}
else {
InstructionAdapter iv = new InstructionAdapter(mv);
Type type = typeMapper.mapType(propertyDescriptor);
int paramCode = 0;
if (kind != OwnerKind.NAMESPACE) {
iv.load(0, OBJECT_TYPE);
paramCode = 1;
}
ReceiverParameterDescriptor receiverParameter = propertyDescriptor.getReceiverParameter();
if (receiverParameter != null) {
paramCode += typeMapper.mapType(receiverParameter.getType()).getSize();
}
iv.load(paramCode, type);
iv.visitFieldInsn(kind == OwnerKind.NAMESPACE ? PUTSTATIC : PUTFIELD,
typeMapper.getOwner(propertyDescriptor, kind, isCallInsideSameModuleAsDeclared(propertyDescriptor, context)).getInternalName(),
propertyDescriptor.getName().getName(),
type.getDescriptor());
iv.visitInsn(RETURN);
}
}
FunctionCodegen.endVisit(mv, "setter", origin);
FunctionCodegen.generateBridgeIfNeeded(context, state, v, jvmMethodSignature.getAsmMethod(), setter);
}
}
public static String getterName(Name propertyName) {
return JvmAbi.GETTER_PREFIX + StringUtil.capitalizeWithJavaBeanConvention(propertyName.getName());
}