Refactor codegen of property backing fields, TImpl, etc.

- remove synthetic method code generation from TraitImplBodyCodegen, use
  PropertyCodegen for that
- don't try to generate synthetic methods for constructor properties
- inline methods, NotNull, renames, etc.
This commit is contained in:
Alexander Udalov
2013-10-17 17:39:40 +04:00
parent b7789da3b9
commit b8db438db1
3 changed files with 45 additions and 74 deletions
@@ -81,7 +81,8 @@ public abstract class ClassBodyCodegen extends MemberCodegen {
protected abstract void generateKotlinAnnotation();
protected abstract void generateSyntheticParts();
protected void generateSyntheticParts() {
}
private void generateClassBody() {
FunctionCodegen functionCodegen = new FunctionCodegen(context, v, state, this);
@@ -94,8 +94,8 @@ public class PropertyCodegen extends GenerationStateAware {
Type ownerType = ((NamespaceFacadeContext) context).getDelegateToClassType();
v.getMemberMap().recordImplClassNameForCallable(propertyDescriptor, shortNameByAsmType(ownerType));
}
else if (kind != OwnerKind.TRAIT_IMPL) {
generateBackingField(p, propertyDescriptor);
else if (!generateBackingField(p, propertyDescriptor)) {
generateSyntheticMethodIfNeeded(propertyDescriptor);
}
generateGetter(p, propertyDescriptor, p.getGetter());
@@ -126,60 +126,55 @@ public class PropertyCodegen extends GenerationStateAware {
}
}
private void generateBackingField(JetNamedDeclaration p, PropertyDescriptor propertyDescriptor) {
boolean hasBackingField = Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor));
boolean isDelegated = p instanceof JetProperty && ((JetProperty) p).getDelegateExpression() != null;
if (hasBackingField || isDelegated) {
DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
if (isInterface(containingDeclaration)) {
return;
}
FieldVisitor fieldVisitor = hasBackingField
? generateBackingFieldAccess(p, propertyDescriptor)
: generatePropertyDelegateAccess((JetProperty) p, propertyDescriptor);
AnnotationCodegen.forField(fieldVisitor, typeMapper).genAnnotations(propertyDescriptor);
private boolean generateBackingField(@NotNull JetNamedDeclaration p, @NotNull PropertyDescriptor descriptor) {
if (isInterface(descriptor.getContainingDeclaration()) || kind == OwnerKind.TRAIT_IMPL) {
return false;
}
else if (!propertyDescriptor.getAnnotations().isEmpty()) {
Method method = getSyntheticMethodSignature(typeMapper, propertyDescriptor);
DeclarationDescriptor descriptor = context.getContextDescriptor();
if (isTrait(descriptor)) {
Type tImplType = typeMapper.mapTraitImpl((ClassDescriptor) descriptor);
v.getMemberMap().recordImplClassNameForCallable(propertyDescriptor, shortNameByAsmType(tImplType));
}
else {
generateSyntheticMethodForAnnotatedProperty(v, typeMapper, propertyDescriptor, method);
}
v.getMemberMap().recordSyntheticMethodOfProperty(propertyDescriptor, method);
FieldVisitor fv;
if (Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor))) {
fv = generateBackingFieldAccess(p, descriptor);
}
else if (p instanceof JetProperty && ((JetProperty) p).getDelegateExpression() != null) {
fv = generatePropertyDelegateAccess((JetProperty) p, descriptor);
}
else {
return false;
}
AnnotationCodegen.forField(fv, typeMapper).genAnnotations(descriptor);
return true;
}
// Annotations on properties without backing fields are stored in bytecode on an empty synthetic method. This way they're still
// accessible via reflection, and 'deprecated' and 'private' flags prevent this method from being called accidentally
public static void generateSyntheticMethodForAnnotatedProperty(
@NotNull ClassBuilder v,
@NotNull JetTypeMapper typeMapper,
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull Method method
) {
MethodVisitor mv = v.newMethod(null,
ACC_DEPRECATED | ACC_FINAL | ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC,
method.getName(),
method.getDescriptor(),
null,
null);
AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(propertyDescriptor);
mv.visitCode();
mv.visitInsn(Opcodes.RETURN);
mv.visitEnd();
}
private void generateSyntheticMethodIfNeeded(@NotNull PropertyDescriptor descriptor) {
if (descriptor.getAnnotations().isEmpty()) return;
@NotNull
public static Method getSyntheticMethodSignature(@NotNull JetTypeMapper typeMapper, @NotNull PropertyDescriptor propertyDescriptor) {
ReceiverParameterDescriptor receiver = propertyDescriptor.getReceiverParameter();
ReceiverParameterDescriptor receiver = descriptor.getReceiverParameter();
Type receiverAsmType = receiver == null ? null : typeMapper.mapType(receiver.getType());
return JvmAbi.getSyntheticMethodSignatureForAnnotatedProperty(propertyDescriptor.getName(), receiverAsmType);
Method method = JvmAbi.getSyntheticMethodSignatureForAnnotatedProperty(descriptor.getName(), receiverAsmType);
if (!isTrait(context.getContextDescriptor()) || kind == OwnerKind.TRAIT_IMPL) {
MethodVisitor mv = v.newMethod(null,
ACC_DEPRECATED | ACC_FINAL | ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC,
method.getName(),
method.getDescriptor(),
null,
null);
AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(descriptor);
mv.visitCode();
mv.visitInsn(Opcodes.RETURN);
mv.visitEnd();
}
else {
Type tImplType = typeMapper.mapTraitImpl((ClassDescriptor) context.getContextDescriptor());
v.getMemberMap().recordImplClassNameForCallable(descriptor, shortNameByAsmType(tImplType));
}
if (kind != OwnerKind.TRAIT_IMPL) {
v.getMemberMap().recordSyntheticMethodOfProperty(descriptor, method);
}
}
private FieldVisitor generateBackingField(JetNamedDeclaration element, PropertyDescriptor propertyDescriptor, boolean isDelegate, JetType jetType, Object defaultValue) {
@@ -19,15 +19,9 @@ package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.AnnotationVisitor;
import org.jetbrains.asm4.commons.Method;
import org.jetbrains.jet.codegen.context.ClassContext;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetProperty;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames;
@@ -65,23 +59,4 @@ public class TraitImplBodyCodegen extends ClassBodyCodegen {
av.visit(JvmAnnotationNames.ABI_VERSION_FIELD_NAME, JvmAbi.VERSION);
av.visitEnd();
}
@Override
protected void generateSyntheticParts() {
generateSyntheticMethodsForAnnotatedProperties();
}
private void generateSyntheticMethodsForAnnotatedProperties() {
for (JetDeclaration declaration : myClass.getDeclarations()) {
if (declaration instanceof JetProperty) {
VariableDescriptor variable = bindingContext.get(BindingContext.VARIABLE, declaration);
assert variable instanceof PropertyDescriptor : "Variable in trait should be a property: " + variable;
PropertyDescriptor property = (PropertyDescriptor) variable;
if (!property.getAnnotations().isEmpty()) {
Method method = PropertyCodegen.getSyntheticMethodSignature(typeMapper, property);
PropertyCodegen.generateSyntheticMethodForAnnotatedProperty(v, typeMapper, property, method);
}
}
}
}
}