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();
}
@NotNull
public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper) {
boolean isSingleton = calleeContainingClass.getKind().isSingleton();
if (isSingleton) {
@@ -2227,8 +2228,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
boolean inStartConstructorContext = cur instanceof ConstructorContext;
while (cur != null) {
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);
}
@@ -142,7 +142,7 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
endVisit(mv, null, origin);
generateBridgeIfNeeded(owner, state, v, functionDescriptor);
generateBridgeIfNeeded(functionDescriptor);
methodContext.recordSyntheticAccessorIfNeeded(functionDescriptor, bindingContext);
}
@@ -404,12 +404,7 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
return bytecode;
}
static void generateBridgeIfNeeded(
CodegenContext owner,
GenerationState state,
ClassBuilder v,
FunctionDescriptor functionDescriptor
) {
private void generateBridgeIfNeeded(@NotNull FunctionDescriptor functionDescriptor) {
if (owner.getContextKind() == OwnerKind.TRAIT_IMPL) {
return;
}
@@ -775,6 +770,6 @@ public class FunctionCodegen extends ParentCodegenAwareImpl {
endVisit(mv, "Delegate method " + functionDescriptor + " to " + jvmOverriddenMethodSignature,
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.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
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.binding.CodegenBinding.*;
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.DescriptorUtils.*;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE;
@@ -1464,21 +1462,28 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
private void generateTraitMethods() {
if (JetPsiUtil.isTrait(myClass)) {
return;
}
if (JetPsiUtil.isTrait(myClass)) return;
for (Pair<CallableMemberDescriptor, CallableMemberDescriptor> needDelegates : getTraitImplementations(descriptor)) {
if (needDelegates.second instanceof SimpleFunctionDescriptor) {
generateDelegationToTraitImpl((FunctionDescriptor) needDelegates.second, (FunctionDescriptor) needDelegates.first);
for (Pair<CallableMemberDescriptor, CallableMemberDescriptor> pair : getTraitImplementations(descriptor)) {
CallableMemberDescriptor inheritedMember = pair.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) {
PropertyDescriptor property = (PropertyDescriptor) needDelegates.second;
List<PropertyAccessorDescriptor> inheritedAccessors = ((PropertyDescriptor) needDelegates.first).getAccessors();
for (PropertyAccessorDescriptor accessor : property.getAccessors()) {
for (PropertyAccessorDescriptor inheritedAccessor : inheritedAccessors) {
if (inheritedAccessor.getClass() == accessor.getClass()) { // same accessor kind
generateDelegationToTraitImpl(accessor, inheritedAccessor);
else if (traitMember instanceof PropertyDescriptor) {
for (PropertyAccessorDescriptor traitAccessor : ((PropertyDescriptor) traitMember).getAccessors()) {
for (PropertyAccessorDescriptor inheritedAccessor : ((PropertyDescriptor) copy).getAccessors()) {
if (inheritedAccessor.getClass() == traitAccessor.getClass()) { // same accessor kind
generateDelegationToTraitImpl(traitAccessor, 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) {
DeclarationDescriptor containingDeclaration = fun.getContainingDeclaration();
if (!(containingDeclaration instanceof ClassDescriptor)) {
return;
}
Method traitMethod = typeMapper.mapSignature(traitFun.getOriginal()).getAsmMethod();
ClassDescriptor containingClass = (ClassDescriptor) containingDeclaration;
if (containingClass.getKind() != ClassKind.TRAIT) {
return;
}
Type[] argTypes = signature.getAsmMethod().getArgumentTypes();
Type[] originalArgTypes = traitMethod.getArgumentTypes();
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();
Method methodInTrait = typeMapper.mapSignature(fun.getOriginal()).getAsmMethod();
Type type = getTraitImplThisParameterType(containingTrait, typeMapper);
String desc = traitMethod.getDescriptor().replace("(", "(" + type.getDescriptor());
PsiElement origin = descriptorToDeclaration(bindingContext, fun);
MethodVisitor mv = v.newMethod(origin, flags, methodToGenerate.getName(), methodToGenerate.getDescriptor(), null,
CodegenUtil.getExceptions(fun, typeMapper));
AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(fun);
iv.invokestatic(typeMapper.mapTraitImpl(containingTrait).getInternalName(), traitMethod.getName(), desc);
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
Type returnType = methodToGenerate.getReturnType();
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 returnType = signature.getReturnType();
StackValue.onStack(traitMethod.getReturnType()).put(returnType, iv);
iv.areturn(returnType);
}
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(
@@ -19,7 +19,6 @@ package org.jetbrains.jet.lang.resolve;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
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.TypeUtils;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.*;
import static org.jetbrains.jet.lang.diagnostics.Errors.MANY_IMPL_MEMBER_NOT_IMPLEMENTED;
import static org.jetbrains.jet.lang.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE;
@@ -162,11 +158,11 @@ public final class DelegationResolver<T extends CallableMemberDescriptor> {
@NotNull
private Collection<T> generateDelegationCandidates(@NotNull JetType delegatedTraitType) {
Collection<T> descriptorsToDelegate = overridableMembersNotFromSuperClassOfTrait(delegatedTraitType);
Collection<T> result = Lists.newArrayList();
Collection<T> result = new ArrayList<T>(descriptorsToDelegate.size());
for (T memberDescriptor : descriptorsToDelegate) {
Modality modality = DescriptorUtils.convertModality(memberDescriptor.getModality(), true);
Modality newModality = memberDescriptor.getModality() == Modality.ABSTRACT ? Modality.OPEN : memberDescriptor.getModality();
@SuppressWarnings("unchecked")
T copy = (T) memberDescriptor.copy(ownerDescriptor, modality, memberDescriptor.getVisibility(),
T copy = (T) memberDescriptor.copy(ownerDescriptor, newModality, memberDescriptor.getVisibility(),
CallableMemberDescriptor.Kind.DELEGATION, false);
result.add(copy);
}
@@ -23,7 +23,6 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
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.name.Name;
import org.jetbrains.jet.lang.types.DescriptorSubstitutor;
@@ -243,16 +242,17 @@ public class PropertyDescriptorImpl extends VariableDescriptorImpl implements Pr
substitutedDescriptor.setType(outType, substitutedTypeParameters, substitutedExpectedThisObject, substitutedReceiverType);
PropertyGetterDescriptorImpl newGetter = getter == null ? null : new PropertyGetterDescriptorImpl(
substitutedDescriptor, getter.getAnnotations(),
DescriptorUtils.convertModality(getter.getModality(), false), convertVisibility(getter.getVisibility(), newVisibility),
getter.hasBody(), getter.isDefault(), kind, getter.getOriginal());
substitutedDescriptor, getter.getAnnotations(), newModality, convertVisibility(getter.getVisibility(), newVisibility),
getter.hasBody(), getter.isDefault(), kind, getter.getOriginal()
);
if (newGetter != null) {
JetType returnType = getter.getReturnType();
newGetter.initialize(returnType != null ? substitutor.substitute(returnType, Variance.OUT_VARIANCE) : null);
}
PropertySetterDescriptorImpl newSetter = setter == null ? null : new PropertySetterDescriptorImpl(
substitutedDescriptor, setter.getAnnotations(), DescriptorUtils.convertModality(setter.getModality(), false),
convertVisibility(setter.getVisibility(), newVisibility), setter.hasBody(), setter.isDefault(), kind, setter.getOriginal());
substitutedDescriptor, setter.getAnnotations(), newModality, convertVisibility(setter.getVisibility(), newVisibility),
setter.hasBody(), setter.isDefault(), kind, setter.getOriginal()
);
if (newSetter != null) {
List<ValueParameterDescriptor> substitutedValueParameters = FunctionDescriptorImpl.getSubstitutedValueParameters(newSetter, setter, substitutor);
if (substitutedValueParameters == null) {
@@ -57,12 +57,6 @@ public class DescriptorUtils {
return substitutedFunction;
}
@NotNull
public static Modality convertModality(@NotNull Modality modality, boolean makeNonAbstract) {
if (makeNonAbstract && modality == Modality.ABSTRACT) return Modality.OPEN;
return modality;
}
@Nullable
public static ReceiverParameterDescriptor getExpectedThisObjectIfNeeded(@NotNull DeclarationDescriptor containingDeclaration) {
if (containingDeclaration instanceof ClassDescriptor) {