Refactor: pull up and extract method
This commit is contained in:
@@ -5,11 +5,13 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.codegen;
|
package org.jetbrains.kotlin.codegen;
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
import kotlin.collections.CollectionsKt;
|
import kotlin.collections.CollectionsKt;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
||||||
import org.jetbrains.kotlin.backend.common.bridges.ImplKt;
|
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.context.ClassContext;
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
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.psi.synthetics.SyntheticClassOrObjectDescriptorKt;
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
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.DescriptorKindFilter;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
|
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.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface;
|
||||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.enumEntryNeedSubclass;
|
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<KtPureClassOrObject> {
|
public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject> {
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -204,4 +213,78 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtPureClassOrObject
|
|||||||
protected ClassDescriptor classForInnerClassRecord() {
|
protected ClassDescriptor classForInnerClassRecord() {
|
||||||
return InnerClassConsumer.Companion.classForInnerClassRecord(descriptor, false);
|
return InnerClassConsumer.Companion.classForInnerClassRecord(descriptor, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void generateTraitMethods() {
|
||||||
|
if (isJvmInterface(descriptor)) return;
|
||||||
|
|
||||||
|
for (Map.Entry<FunctionDescriptor, FunctionDescriptor> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1051,71 +1051,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateTraitMethods() {
|
|
||||||
if (isJvmInterface(descriptor)) return;
|
|
||||||
|
|
||||||
for (Map.Entry<FunctionDescriptor, FunctionDescriptor> 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() {
|
private void generateEnumEntries() {
|
||||||
if (descriptor.getKind() != ClassKind.ENUM_CLASS) return;
|
if (descriptor.getKind() != ClassKind.ENUM_CLASS) return;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user