diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBodyCodegen.java index 60596fa41f3..74e5e99cb40 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBodyCodegen.java @@ -5,11 +5,13 @@ package org.jetbrains.kotlin.codegen; +import com.intellij.psi.PsiElement; import kotlin.collections.CollectionsKt; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.backend.common.CodegenUtil; import org.jetbrains.kotlin.backend.common.bridges.ImplKt; +import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.codegen.context.ClassContext; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.descriptors.*; @@ -18,15 +20,22 @@ import org.jetbrains.kotlin.psi.synthetics.SyntheticClassOrObjectDescriptor; import org.jetbrains.kotlin.psi.synthetics.SyntheticClassOrObjectDescriptorKt; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.DescriptorUtils; +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter; import org.jetbrains.kotlin.resolve.scopes.MemberScope; +import org.jetbrains.org.objectweb.asm.Type; +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; +import org.jetbrains.org.objectweb.asm.commons.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.util.*; +import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface; import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.enumEntryNeedSubclass; +import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration; +import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE; +import static org.jetbrains.kotlin.resolve.jvm.annotations.JvmAnnotationUtilKt.hasJvmDefaultAnnotation; +import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind.CLASS_MEMBER_DELEGATION_TO_DEFAULT_IMPL; public abstract class ClassBodyCodegen extends MemberCodegen { @NotNull @@ -204,4 +213,78 @@ public abstract class ClassBodyCodegen extends MemberCodegen entry : CodegenUtil.getNonPrivateTraitMethods(descriptor).entrySet()) { + FunctionDescriptor interfaceFun = entry.getKey(); + //skip java 8 default methods + if (!CodegenUtilKt.isDefinitelyNotDefaultImplsMethod(interfaceFun) && !hasJvmDefaultAnnotation(interfaceFun)) { + generateDelegationToDefaultImpl(interfaceFun, entry.getValue()); + } + } + } + + private void generateDelegationToDefaultImpl(@NotNull FunctionDescriptor interfaceFun, @NotNull FunctionDescriptor inheritedFun) { + + functionCodegen.generateMethod( + new JvmDeclarationOrigin(CLASS_MEMBER_DELEGATION_TO_DEFAULT_IMPL, descriptorToDeclaration(interfaceFun), interfaceFun), + inheritedFun, + new FunctionGenerationStrategy.CodegenBased(state) { + @Override + public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { + DeclarationDescriptor containingDeclaration = interfaceFun.getContainingDeclaration(); + if (!DescriptorUtils.isInterface(containingDeclaration)) return; + + DeclarationDescriptor declarationInheritedFun = inheritedFun.getContainingDeclaration(); + PsiElement classForInheritedFun = descriptorToDeclaration(declarationInheritedFun); + if (classForInheritedFun instanceof KtDeclaration) { + codegen.markLineNumber((KtElement) classForInheritedFun, false); + } + + ClassDescriptor containingTrait = (ClassDescriptor) containingDeclaration; + Type traitImplType = typeMapper.mapDefaultImpls(containingTrait); + + FunctionDescriptor originalInterfaceFun = interfaceFun.getOriginal(); + Method traitMethod = typeMapper.mapAsmMethod(originalInterfaceFun, OwnerKind.DEFAULT_IMPLS); + + putArgumentsOnStack(codegen, signature, traitMethod); + InstructionAdapter iv = codegen.v; + + if (KotlinBuiltIns.isCloneable(containingTrait) && traitMethod.getName().equals("clone")) { + // A special hack for Cloneable: there's no kotlin/Cloneable$DefaultImpls class at runtime, + // and its 'clone' method is actually located in java/lang/Object + iv.invokespecial("java/lang/Object", "clone", "()Ljava/lang/Object;", false); + } + else { + iv.invokestatic(traitImplType.getInternalName(), traitMethod.getName(), traitMethod.getDescriptor(), false); + } + + Type returnType = signature.getReturnType(); + StackValue.onStack(traitMethod.getReturnType(), originalInterfaceFun.getReturnType()).put(returnType, iv); + iv.areturn(returnType); + } + + private void putArgumentsOnStack( + @NotNull ExpressionCodegen codegen, + @NotNull JvmMethodSignature signature, + Method traitMethod + ) { + InstructionAdapter iv = codegen.v; + Type[] argTypes = signature.getAsmMethod().getArgumentTypes(); + Type[] originalArgTypes = traitMethod.getArgumentTypes(); + assert originalArgTypes.length == argTypes.length + 1 : + "Invalid trait implementation signature: " + signature + " vs " + traitMethod + " for " + interfaceFun; + + iv.load(0, OBJECT_TYPE); + for (int i = 0, reg = 1; i < argTypes.length; i++) { + StackValue.local(reg, argTypes[i]).put(originalArgTypes[i + 1], iv); + //noinspection AssignmentToForLoopParameter + reg += argTypes[i].getSize(); + } + } + } + ); + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index a11d82bd3ec..9b78bd54308 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -1051,71 +1051,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } } - private void generateTraitMethods() { - if (isJvmInterface(descriptor)) return; - - for (Map.Entry entry : CodegenUtil.getNonPrivateTraitMethods(descriptor).entrySet()) { - FunctionDescriptor interfaceFun = entry.getKey(); - //skip java 8 default methods - if (!CodegenUtilKt.isDefinitelyNotDefaultImplsMethod(interfaceFun) && !hasJvmDefaultAnnotation(interfaceFun)) { - generateDelegationToDefaultImpl(interfaceFun, entry.getValue()); - } - } - } - - private void generateDelegationToDefaultImpl(@NotNull FunctionDescriptor interfaceFun, @NotNull FunctionDescriptor inheritedFun) { - - functionCodegen.generateMethod( - new JvmDeclarationOrigin(CLASS_MEMBER_DELEGATION_TO_DEFAULT_IMPL, descriptorToDeclaration(interfaceFun), interfaceFun), - inheritedFun, - new FunctionGenerationStrategy.CodegenBased(state) { - @Override - public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { - DeclarationDescriptor containingDeclaration = interfaceFun.getContainingDeclaration(); - if (!DescriptorUtils.isInterface(containingDeclaration)) return; - - DeclarationDescriptor declarationInheritedFun = inheritedFun.getContainingDeclaration(); - PsiElement classForInheritedFun = descriptorToDeclaration(declarationInheritedFun); - if (classForInheritedFun instanceof KtDeclaration) { - codegen.markLineNumber((KtElement) classForInheritedFun, false); - } - - ClassDescriptor containingTrait = (ClassDescriptor) containingDeclaration; - Type traitImplType = typeMapper.mapDefaultImpls(containingTrait); - - FunctionDescriptor originalInterfaceFun = interfaceFun.getOriginal(); - Method traitMethod = typeMapper.mapAsmMethod(originalInterfaceFun, OwnerKind.DEFAULT_IMPLS); - - Type[] argTypes = signature.getAsmMethod().getArgumentTypes(); - Type[] originalArgTypes = traitMethod.getArgumentTypes(); - assert originalArgTypes.length == argTypes.length + 1 : - "Invalid trait implementation signature: " + signature + " vs " + traitMethod + " for " + interfaceFun; - - 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 + 1], iv); - //noinspection AssignmentToForLoopParameter - reg += argTypes[i].getSize(); - } - - if (KotlinBuiltIns.isCloneable(containingTrait) && traitMethod.getName().equals("clone")) { - // A special hack for Cloneable: there's no kotlin/Cloneable$DefaultImpls class at runtime, - // and its 'clone' method is actually located in java/lang/Object - iv.invokespecial("java/lang/Object", "clone", "()Ljava/lang/Object;", false); - } - else { - iv.invokestatic(traitImplType.getInternalName(), traitMethod.getName(), traitMethod.getDescriptor(), false); - } - - Type returnType = signature.getReturnType(); - StackValue.onStack(traitMethod.getReturnType(), originalInterfaceFun.getReturnType()).put(returnType, iv); - iv.areturn(returnType); - } - } - ); - } - private void generateEnumEntries() { if (descriptor.getKind() != ClassKind.ENUM_CLASS) return;