Simplify codegen for trait methods with implementations

- use existing framework (FunctionCodegen.generateMethod) which will take care
  of all subtleties of method generation (bridges, annotations, thrown
  exceptions, etc)
- call to "generateThisOrOuter" was not needed, since when we're generating
  delegation to TImpl, "this" is always "ALOAD 0"
This commit is contained in:
Alexander Udalov
2014-03-24 21:15:40 +04:00
parent 089cba5791
commit 11386c0f7a
6 changed files with 69 additions and 90 deletions
@@ -2210,6 +2210,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@NotNull
public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper) { public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper) {
boolean isSingleton = calleeContainingClass.getKind().isSingleton(); boolean isSingleton = calleeContainingClass.getKind().isSingleton();
if (isSingleton) { if (isSingleton) {
@@ -2227,8 +2228,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
boolean inStartConstructorContext = cur instanceof ConstructorContext; boolean inStartConstructorContext = cur instanceof ConstructorContext;
while (cur != null) { while (cur != null) {
ClassDescriptor thisDescriptor = cur.getThisDescriptor(); ClassDescriptor thisDescriptor = cur.getThisDescriptor();
if (!isSuper && thisDescriptor.equals(calleeContainingClass)
|| isSuper && DescriptorUtils.isSubclass(thisDescriptor, calleeContainingClass)) { if (!isSuper && thisDescriptor == calleeContainingClass) {
return result;
}
if (isSuper && DescriptorUtils.isSubclass(thisDescriptor, calleeContainingClass)) {
return castToRequiredTypeOfInterfaceIfNeeded(result, thisDescriptor, calleeContainingClass); return castToRequiredTypeOfInterfaceIfNeeded(result, thisDescriptor, calleeContainingClass);
} }
@@ -142,7 +142,7 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
endVisit(mv, null, origin); endVisit(mv, null, origin);
generateBridgeIfNeeded(owner, state, v, functionDescriptor); generateBridgeIfNeeded(functionDescriptor);
methodContext.recordSyntheticAccessorIfNeeded(functionDescriptor, bindingContext); methodContext.recordSyntheticAccessorIfNeeded(functionDescriptor, bindingContext);
} }
@@ -404,12 +404,7 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
return bytecode; return bytecode;
} }
static void generateBridgeIfNeeded( private void generateBridgeIfNeeded(@NotNull FunctionDescriptor functionDescriptor) {
CodegenContext owner,
GenerationState state,
ClassBuilder v,
FunctionDescriptor functionDescriptor
) {
if (owner.getContextKind() == OwnerKind.TRAIT_IMPL) { if (owner.getContextKind() == OwnerKind.TRAIT_IMPL) {
return; return;
} }
@@ -775,6 +770,6 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
endVisit(mv, "Delegate method " + functionDescriptor + " to " + jvmOverriddenMethodSignature, endVisit(mv, "Delegate method " + functionDescriptor + " to " + jvmOverriddenMethodSignature,
descriptorToDeclaration(bindingContext, functionDescriptor.getContainingDeclaration())); descriptorToDeclaration(bindingContext, functionDescriptor.getContainingDeclaration()));
generateBridgeIfNeeded(owner, state, v, functionDescriptor); generateBridgeIfNeeded(functionDescriptor);
} }
} }
@@ -20,7 +20,6 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.util.ArrayUtil; import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -64,7 +63,6 @@ import static org.jetbrains.jet.codegen.AsmUtil.*;
import static org.jetbrains.jet.codegen.CodegenUtil.*; import static org.jetbrains.jet.codegen.CodegenUtil.*;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
import static org.jetbrains.jet.descriptors.serialization.NameSerializationUtil.createNameResolver; import static org.jetbrains.jet.descriptors.serialization.NameSerializationUtil.createNameResolver;
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration;
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration; import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE;
@@ -1464,21 +1462,28 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
private void generateTraitMethods() { private void generateTraitMethods() {
if (JetPsiUtil.isTrait(myClass)) { if (JetPsiUtil.isTrait(myClass)) return;
return;
}
for (Pair<CallableMemberDescriptor, CallableMemberDescriptor> needDelegates : getTraitImplementations(descriptor)) { for (Pair<CallableMemberDescriptor, CallableMemberDescriptor> pair : getTraitImplementations(descriptor)) {
if (needDelegates.second instanceof SimpleFunctionDescriptor) { CallableMemberDescriptor inheritedMember = pair.first;
generateDelegationToTraitImpl((FunctionDescriptor) needDelegates.second, (FunctionDescriptor) needDelegates.first); CallableMemberDescriptor traitMember = pair.second;
assert traitMember.getModality() != Modality.ABSTRACT : "Cannot delegate to abstract trait method: " + pair;
// inheritedMember can be abstract here. In order for FunctionCodegen to generate the method body, we're creating a copy here
// with traitMember's modality
CallableMemberDescriptor copy =
inheritedMember.copy(inheritedMember.getContainingDeclaration(), traitMember.getModality(), Visibilities.PUBLIC,
CallableMemberDescriptor.Kind.DECLARATION, true);
if (traitMember instanceof SimpleFunctionDescriptor) {
generateDelegationToTraitImpl((FunctionDescriptor) traitMember, (FunctionDescriptor) copy);
} }
else if (needDelegates.second instanceof PropertyDescriptor) { else if (traitMember instanceof PropertyDescriptor) {
PropertyDescriptor property = (PropertyDescriptor) needDelegates.second; for (PropertyAccessorDescriptor traitAccessor : ((PropertyDescriptor) traitMember).getAccessors()) {
List<PropertyAccessorDescriptor> inheritedAccessors = ((PropertyDescriptor) needDelegates.first).getAccessors(); for (PropertyAccessorDescriptor inheritedAccessor : ((PropertyDescriptor) copy).getAccessors()) {
for (PropertyAccessorDescriptor accessor : property.getAccessors()) { if (inheritedAccessor.getClass() == traitAccessor.getClass()) { // same accessor kind
for (PropertyAccessorDescriptor inheritedAccessor : inheritedAccessors) { generateDelegationToTraitImpl(traitAccessor, inheritedAccessor);
if (inheritedAccessor.getClass() == accessor.getClass()) { // same accessor kind
generateDelegationToTraitImpl(accessor, inheritedAccessor);
} }
} }
} }
@@ -1486,58 +1491,42 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
} }
private void generateDelegationToTraitImpl(@NotNull final FunctionDescriptor traitFun, @NotNull FunctionDescriptor inheritedFun) {
functionCodegen.generateMethod(
descriptorToDeclaration(bindingContext, traitFun),
typeMapper.mapSignature(inheritedFun),
inheritedFun,
new FunctionGenerationStrategy.CodegenBased<FunctionDescriptor>(state, inheritedFun) {
@Override
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
DeclarationDescriptor containingDeclaration = traitFun.getContainingDeclaration();
if (!(containingDeclaration instanceof ClassDescriptor)) return;
ClassDescriptor containingTrait = (ClassDescriptor) containingDeclaration;
if (containingTrait.getKind() != ClassKind.TRAIT) return;
private void generateDelegationToTraitImpl(@NotNull FunctionDescriptor fun, @NotNull FunctionDescriptor inheritedFun) { Method traitMethod = typeMapper.mapSignature(traitFun.getOriginal()).getAsmMethod();
DeclarationDescriptor containingDeclaration = fun.getContainingDeclaration();
if (!(containingDeclaration instanceof ClassDescriptor)) {
return;
}
ClassDescriptor containingClass = (ClassDescriptor) containingDeclaration; Type[] argTypes = signature.getAsmMethod().getArgumentTypes();
if (containingClass.getKind() != ClassKind.TRAIT) { Type[] originalArgTypes = traitMethod.getArgumentTypes();
return;
}
int flags = ACC_PUBLIC; // TODO. InstructionAdapter iv = codegen.v;
iv.load(0, OBJECT_TYPE);
for (int i = 0, reg = 1; i < argTypes.length; i++) {
StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
//noinspection AssignmentToForLoopParameter
reg += argTypes[i].getSize();
}
Method methodToGenerate = typeMapper.mapSignature(fun).getAsmMethod(); Type type = getTraitImplThisParameterType(containingTrait, typeMapper);
Method methodInTrait = typeMapper.mapSignature(fun.getOriginal()).getAsmMethod(); String desc = traitMethod.getDescriptor().replace("(", "(" + type.getDescriptor());
PsiElement origin = descriptorToDeclaration(bindingContext, fun); iv.invokestatic(typeMapper.mapTraitImpl(containingTrait).getInternalName(), traitMethod.getName(), desc);
MethodVisitor mv = v.newMethod(origin, flags, methodToGenerate.getName(), methodToGenerate.getDescriptor(), null,
CodegenUtil.getExceptions(fun, typeMapper));
AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(fun);
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { Type returnType = signature.getReturnType();
Type returnType = methodToGenerate.getReturnType(); StackValue.onStack(traitMethod.getReturnType()).put(returnType, iv);
iv.areturn(returnType);
mv.visitCode();
FrameMap frameMap = context.prepareFrame(typeMapper);
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, returnType, context.intoFunction(inheritedFun), state, this);
codegen.generateThisOrOuter(descriptor, false); // ??? wouldn't it be addClosureToConstructorParameters good idea to put it?
Type[] argTypes = methodToGenerate.getArgumentTypes();
Type[] originalArgTypes = methodInTrait.getArgumentTypes();
InstructionAdapter iv = new InstructionAdapter(mv);
iv.load(0, OBJECT_TYPE);
for (int i = 0, reg = 1; i < argTypes.length; i++) {
StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
//noinspection AssignmentToForLoopParameter
reg += argTypes[i].getSize();
} }
});
Type type = getTraitImplThisParameterType(containingClass, typeMapper);
String functionDescriptor = methodInTrait.getDescriptor().replace("(", "(" + type.getDescriptor());
iv.invokestatic(typeMapper.mapTraitImpl(containingClass).getInternalName(), methodToGenerate.getName(), functionDescriptor);
StackValue.onStack(methodInTrait.getReturnType()).put(returnType, iv);
iv.areturn(returnType);
FunctionCodegen.endVisit(iv, "trait method", callableDescriptorToDeclaration(bindingContext, fun));
}
FunctionCodegen.generateBridgeIfNeeded(context, state, v, fun);
} }
private void generateDelegatorToConstructorCall( private void generateDelegatorToConstructorCall(
@@ -19,7 +19,6 @@ package org.jetbrains.jet.lang.resolve;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Collections2; import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -32,10 +31,7 @@ import org.jetbrains.jet.lang.psi.JetTypeReference;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeUtils; import org.jetbrains.jet.lang.types.TypeUtils;
import java.util.Collection; import java.util.*;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import static org.jetbrains.jet.lang.diagnostics.Errors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED; import static org.jetbrains.jet.lang.diagnostics.Errors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED;
import static org.jetbrains.jet.lang.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE; import static org.jetbrains.jet.lang.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE;
@@ -162,11 +158,11 @@ public final class DelegationResolver<T extends CallableMemberDescriptor> {
@NotNull @NotNull
private Collection<T> generateDelegationCandidates(@NotNull JetType delegatedTraitType) { private Collection<T> generateDelegationCandidates(@NotNull JetType delegatedTraitType) {
Collection<T> descriptorsToDelegate = overridableMembersNotFromSuperClassOfTrait(delegatedTraitType); Collection<T> descriptorsToDelegate = overridableMembersNotFromSuperClassOfTrait(delegatedTraitType);
Collection<T> result = Lists.newArrayList(); Collection<T> result = new ArrayList<T>(descriptorsToDelegate.size());
for (T memberDescriptor : descriptorsToDelegate) { for (T memberDescriptor : descriptorsToDelegate) {
Modality modality = DescriptorUtils.convertModality(memberDescriptor.getModality(), true); Modality newModality = memberDescriptor.getModality() == Modality.ABSTRACT ? Modality.OPEN : memberDescriptor.getModality();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
T copy = (T) memberDescriptor.copy(ownerDescriptor, modality, memberDescriptor.getVisibility(), T copy = (T) memberDescriptor.copy(ownerDescriptor, newModality, memberDescriptor.getVisibility(),
CallableMemberDescriptor.Kind.DELEGATION, false); CallableMemberDescriptor.Kind.DELEGATION, false);
result.add(copy); result.add(copy);
} }
@@ -23,7 +23,6 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.Annotations; import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
import org.jetbrains.jet.lang.resolve.DescriptorFactory; import org.jetbrains.jet.lang.resolve.DescriptorFactory;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.OverridingUtil; import org.jetbrains.jet.lang.resolve.OverridingUtil;
import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.DescriptorSubstitutor; import org.jetbrains.jet.lang.types.DescriptorSubstitutor;
@@ -243,16 +242,17 @@ public class PropertyDescriptorImpl extends VariableDescriptorImpl implements Pr
substitutedDescriptor.setType(outType, substitutedTypeParameters, substitutedExpectedThisObject, substitutedReceiverType); substitutedDescriptor.setType(outType, substitutedTypeParameters, substitutedExpectedThisObject, substitutedReceiverType);
PropertyGetterDescriptorImpl newGetter = getter == null ? null : new PropertyGetterDescriptorImpl( PropertyGetterDescriptorImpl newGetter = getter == null ? null : new PropertyGetterDescriptorImpl(
substitutedDescriptor, getter.getAnnotations(), substitutedDescriptor, getter.getAnnotations(), newModality, convertVisibility(getter.getVisibility(), newVisibility),
DescriptorUtils.convertModality(getter.getModality(), false), convertVisibility(getter.getVisibility(), newVisibility), getter.hasBody(), getter.isDefault(), kind, getter.getOriginal()
getter.hasBody(), getter.isDefault(), kind, getter.getOriginal()); );
if (newGetter != null) { if (newGetter != null) {
JetType returnType = getter.getReturnType(); JetType returnType = getter.getReturnType();
newGetter.initialize(returnType != null ? substitutor.substitute(returnType, Variance.OUT_VARIANCE) : null); newGetter.initialize(returnType != null ? substitutor.substitute(returnType, Variance.OUT_VARIANCE) : null);
} }
PropertySetterDescriptorImpl newSetter = setter == null ? null : new PropertySetterDescriptorImpl( PropertySetterDescriptorImpl newSetter = setter == null ? null : new PropertySetterDescriptorImpl(
substitutedDescriptor, setter.getAnnotations(), DescriptorUtils.convertModality(setter.getModality(), false), substitutedDescriptor, setter.getAnnotations(), newModality, convertVisibility(setter.getVisibility(), newVisibility),
convertVisibility(setter.getVisibility(), newVisibility), setter.hasBody(), setter.isDefault(), kind, setter.getOriginal()); setter.hasBody(), setter.isDefault(), kind, setter.getOriginal()
);
if (newSetter != null) { if (newSetter != null) {
List<ValueParameterDescriptor> substitutedValueParameters = FunctionDescriptorImpl.getSubstitutedValueParameters(newSetter, setter, substitutor); List<ValueParameterDescriptor> substitutedValueParameters = FunctionDescriptorImpl.getSubstitutedValueParameters(newSetter, setter, substitutor);
if (substitutedValueParameters == null) { if (substitutedValueParameters == null) {
@@ -57,12 +57,6 @@ public class DescriptorUtils {
return substitutedFunction; return substitutedFunction;
} }
@NotNull
public static Modality convertModality(@NotNull Modality modality, boolean makeNonAbstract) {
if (makeNonAbstract && modality == Modality.ABSTRACT) return Modality.OPEN;
return modality;
}
@Nullable @Nullable
public static ReceiverParameterDescriptor getExpectedThisObjectIfNeeded(@NotNull DeclarationDescriptor containingDeclaration) { public static ReceiverParameterDescriptor getExpectedThisObjectIfNeeded(@NotNull DeclarationDescriptor containingDeclaration) {
if (containingDeclaration instanceof ClassDescriptor) { if (containingDeclaration instanceof ClassDescriptor) {