Skip to content

Commit

Permalink
Simplify codegen for trait methods with implementations
Browse files Browse the repository at this point in the history
- 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"
  • Loading branch information
udalov committed Apr 11, 2014
1 parent 089cba5 commit 11386c0
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 93 deletions.
Expand Up @@ -2210,6 +2210,7 @@ private void generateScript(@NotNull ScriptReceiver receiver) {
throw new UnsupportedOperationException();
}

@NotNull
public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper) {
boolean isSingleton = calleeContainingClass.getKind().isSingleton();
if (isSingleton) {
Expand All @@ -2227,8 +2228,12 @@ public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingC
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);
}

Expand Down
Expand Up @@ -142,7 +142,7 @@ public void generateMethod(

endVisit(mv, null, origin);

generateBridgeIfNeeded(owner, state, v, functionDescriptor);
generateBridgeIfNeeded(functionDescriptor);

methodContext.recordSyntheticAccessorIfNeeded(functionDescriptor, bindingContext);
}
Expand Down Expand Up @@ -404,12 +404,7 @@ private static String renderByteCodeIfAvailable(MethodVisitor mv) {
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;
}
Expand Down Expand Up @@ -775,6 +770,6 @@ public void genDelegate(
endVisit(mv, "Delegate method " + functionDescriptor + " to " + jvmOverriddenMethodSignature,
descriptorToDeclaration(bindingContext, functionDescriptor.getContainingDeclaration()));

generateBridgeIfNeeded(owner, state, v, functionDescriptor);
generateBridgeIfNeeded(functionDescriptor);
}
}
Expand Up @@ -20,7 +20,6 @@
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;
Expand Down Expand Up @@ -64,7 +63,6 @@
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;
Expand Down Expand Up @@ -1464,80 +1462,71 @@ private boolean ignoreIfTraitOrAnnotation() {
}

private void generateTraitMethods() {
if (JetPsiUtil.isTrait(myClass)) {
return;
}
if (JetPsiUtil.isTrait(myClass)) return;

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;

for (Pair<CallableMemberDescriptor, CallableMemberDescriptor> needDelegates : getTraitImplementations(descriptor)) {
if (needDelegates.second instanceof SimpleFunctionDescriptor) {
generateDelegationToTraitImpl((FunctionDescriptor) needDelegates.second, (FunctionDescriptor) needDelegates.first);
// 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);
}
}
}
}
}
}

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;

Method traitMethod = typeMapper.mapSignature(traitFun.getOriginal()).getAsmMethod();

Type[] argTypes = signature.getAsmMethod().getArgumentTypes();
Type[] originalArgTypes = traitMethod.getArgumentTypes();

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();
}

private void generateDelegationToTraitImpl(@NotNull FunctionDescriptor fun, @NotNull FunctionDescriptor inheritedFun) {
DeclarationDescriptor containingDeclaration = fun.getContainingDeclaration();
if (!(containingDeclaration instanceof ClassDescriptor)) {
return;
}

ClassDescriptor containingClass = (ClassDescriptor) containingDeclaration;
if (containingClass.getKind() != ClassKind.TRAIT) {
return;
}

int flags = ACC_PUBLIC; // TODO.

Method methodToGenerate = typeMapper.mapSignature(fun).getAsmMethod();
Method methodInTrait = typeMapper.mapSignature(fun.getOriginal()).getAsmMethod();

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);

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 type = getTraitImplThisParameterType(containingTrait, typeMapper);
String desc = traitMethod.getDescriptor().replace("(", "(" + type.getDescriptor());

Type[] argTypes = methodToGenerate.getArgumentTypes();
Type[] originalArgTypes = methodInTrait.getArgumentTypes();
iv.invokestatic(typeMapper.mapTraitImpl(containingTrait).getInternalName(), traitMethod.getName(), desc);

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(
Expand Down
Expand Up @@ -19,7 +19,6 @@
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;
Expand All @@ -32,10 +31,7 @@
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;
Expand Down Expand Up @@ -162,11 +158,11 @@ private Collection<T> generateDelegatesForTrait(
@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);
}
Expand Down
Expand Up @@ -23,7 +23,6 @@
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;
Expand Down Expand Up @@ -243,16 +242,17 @@ private PropertyDescriptor doSubstitute(
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) {
Expand Down
Expand Up @@ -57,12 +57,6 @@ public static <D extends CallableDescriptor> D substituteBounds(@NotNull D funct
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) {
Expand Down

0 comments on commit 11386c0

Please sign in to comment.