Check method abstractness during bridge generation per method not interface

This commit is contained in:
Mikhael Bogdanov
2018-03-06 12:13:19 +01:00
parent f290b325ee
commit 2a8041e77e
19 changed files with 490 additions and 80 deletions
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
import org.jetbrains.kotlin.codegen.coroutines.SuspendFunctionGenerationStrategy;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.config.JvmTarget;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotated;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
@@ -74,6 +75,7 @@ import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUtilKt.isEf
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.getSourceFromDescriptor;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE;
import static org.jetbrains.kotlin.resolve.jvm.annotations.AnnotationUtilKt.hasJvmDefaultAnnotation;
import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.*;
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
@@ -85,10 +87,12 @@ public class FunctionCodegen {
private final ClassBuilder v;
private final MemberCodegen<?> memberCodegen;
private final Function1<DeclarationDescriptor, Boolean> IS_PURE_INTERFACE_CHECKER = new Function1<DeclarationDescriptor, Boolean>() {
private final Function1<CallableMemberDescriptor, Boolean> DECLARATION_AND_DEFINITION_CHECKER = new Function1<CallableMemberDescriptor, Boolean>() {
@Override
public Boolean invoke(DeclarationDescriptor descriptor) {
return JvmCodegenUtil.isInterfaceWithoutDefaults(descriptor, state);
public Boolean invoke(CallableMemberDescriptor descriptor) {
return !isInterface(descriptor.getContainingDeclaration()) ||
(state.getTarget() != JvmTarget.JVM_1_6 &&
hasJvmDefaultAnnotation(descriptor));
}
};
@@ -938,14 +942,14 @@ public class FunctionCodegen {
private boolean hasSpecialBridgeMethod(@NotNull FunctionDescriptor descriptor) {
if (SpecialBuiltinMembers.getOverriddenBuiltinReflectingJvmDescriptor(descriptor) == null) return false;
return !BuiltinSpecialBridgesUtil.generateBridgesForBuiltinSpecial(
descriptor, typeMapper::mapAsmMethod, IS_PURE_INTERFACE_CHECKER
descriptor, typeMapper::mapAsmMethod, DECLARATION_AND_DEFINITION_CHECKER
).isEmpty();
}
public void generateBridges(@NotNull FunctionDescriptor descriptor) {
if (descriptor instanceof ConstructorDescriptor) return;
if (owner.getContextKind() == OwnerKind.DEFAULT_IMPLS) return;
if (IS_PURE_INTERFACE_CHECKER.invoke(descriptor.getContainingDeclaration())) return;
if (!DECLARATION_AND_DEFINITION_CHECKER.invoke(descriptor)) return;
// equals(Any?), hashCode(), toString() never need bridges
if (isMethodOfAny(descriptor)) return;
@@ -955,7 +959,7 @@ public class FunctionCodegen {
Set<Bridge<Method>> bridgesToGenerate;
if (!isSpecial) {
bridgesToGenerate =
ImplKt.generateBridgesForFunctionDescriptor(descriptor, typeMapper::mapAsmMethod, IS_PURE_INTERFACE_CHECKER);
ImplKt.generateBridgesForFunctionDescriptor(descriptor, typeMapper::mapAsmMethod, DECLARATION_AND_DEFINITION_CHECKER);
if (!bridgesToGenerate.isEmpty()) {
PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null;
boolean isSpecialBridge =
@@ -968,7 +972,7 @@ public class FunctionCodegen {
}
else {
Set<BridgeForBuiltinSpecial<Method>> specials = BuiltinSpecialBridgesUtil.generateBridgesForBuiltinSpecial(
descriptor, typeMapper::mapAsmMethod, IS_PURE_INTERFACE_CHECKER
descriptor, typeMapper::mapAsmMethod, DECLARATION_AND_DEFINITION_CHECKER
);
if (!specials.isEmpty()) {
@@ -1310,7 +1314,7 @@ public class FunctionCodegen {
iv.invokespecial(parentInternalName, delegateTo.getName(), delegateTo.getDescriptor(), false);
}
else {
if (CodegenUtilKt.hasJvmDefaultAnnotation(descriptor)) {
if (hasJvmDefaultAnnotation(descriptor)) {
iv.invokeinterface(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor());
}
else {
@@ -1478,7 +1482,7 @@ public class FunctionCodegen {
assert isInterface(containingDeclaration) : "'processInterfaceMethod' method should be called only for interfaces, but: " +
containingDeclaration;
if (CodegenUtilKt.hasJvmDefaultAnnotation(memberDescriptor)) {
if (hasJvmDefaultAnnotation(memberDescriptor)) {
return kind != OwnerKind.DEFAULT_IMPLS;
} else {
switch (kind) {
@@ -1404,7 +1404,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
private void generateTraitMethods() {
if (isInterfaceWithoutDefaults(descriptor, state)) return;
if (isInterface(descriptor)) return;
for (Map.Entry<FunctionDescriptor, FunctionDescriptor> entry : CodegenUtil.getNonPrivateTraitMethods(descriptor).entrySet()) {
FunctionDescriptor interfaceFun = entry.getKey();
@@ -53,30 +53,6 @@ public class JvmCodegenUtil {
private JvmCodegenUtil() {
}
public static boolean isInterfaceWithoutDefaults(@NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state) {
return isInterfaceWithoutDefaults(descriptor, state.isJvm8Target());
}
private static boolean isInterfaceWithoutDefaults(
@NotNull DeclarationDescriptor descriptor,
boolean isJvm8PlusTarget
) {
if (!DescriptorUtils.isInterface(descriptor)) return false;
if (descriptor instanceof DeserializedClassDescriptor) {
SourceElement source = ((DeserializedClassDescriptor) descriptor).getSource();
if (source instanceof KotlinJvmBinarySourceElement) {
KotlinJvmBinaryClass binaryClass = ((KotlinJvmBinarySourceElement) source).getBinaryClass();
assert binaryClass instanceof FileBasedKotlinClass :
"KotlinJvmBinaryClass should be subclass of FileBasedKotlinClass, but " + binaryClass;
return ((FileBasedKotlinClass) binaryClass).getClassVersion() == Opcodes.V1_6;
}
}
//we can't determine is interface have default methods or not
//we need inspect all methods for jvm target 1.8+
return !isJvm8PlusTarget;
}
public static boolean isNonDefaultInterfaceMember(@NotNull CallableMemberDescriptor descriptor) {
if (!isJvmInterface(descriptor.getContainingDeclaration())) {
return false;
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.backend.common.bridges.DescriptorBasedFunctionHandle
import org.jetbrains.kotlin.backend.common.bridges.findAllReachableDeclarations
import org.jetbrains.kotlin.backend.common.bridges.findConcreteSuperDeclaration
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
@@ -45,16 +44,16 @@ class BridgeForBuiltinSpecial<out Signature : Any>(
object BuiltinSpecialBridgesUtil {
@JvmStatic fun <Signature : Any> generateBridgesForBuiltinSpecial(
function: FunctionDescriptor,
signatureByDescriptor: (FunctionDescriptor) -> Signature,
isBodyOwner: (DeclarationDescriptor) -> Boolean
function: FunctionDescriptor,
signatureByDescriptor: (FunctionDescriptor) -> Signature,
areDeclarationAndDefinitionSame: (CallableMemberDescriptor) -> Boolean
): Set<BridgeForBuiltinSpecial<Signature>> {
val functionHandle = DescriptorBasedFunctionHandle(function, isBodyOwner)
val functionHandle = DescriptorBasedFunctionHandle(function, areDeclarationAndDefinitionSame)
val fake = !functionHandle.isDeclaration
val overriddenBuiltin = function.getOverriddenBuiltinReflectingJvmDescriptor()!!
val reachableDeclarations = findAllReachableDeclarations(function, isBodyOwner)
val reachableDeclarations = findAllReachableDeclarations(function, areDeclarationAndDefinitionSame)
// e.g. `getSize()I`
val methodItself = signatureByDescriptor(function)
@@ -78,8 +77,10 @@ object BuiltinSpecialBridgesUtil {
if (fake) {
for (overridden in function.overriddenDescriptors.map { it.original }) {
if (!DescriptorBasedFunctionHandle(overridden, isBodyOwner).isAbstract) {
commonBridges.removeAll(findAllReachableDeclarations(overridden, isBodyOwner).map(signatureByDescriptor))
if (!DescriptorBasedFunctionHandle(overridden, areDeclarationAndDefinitionSame).isAbstract) {
commonBridges.removeAll(findAllReachableDeclarations(overridden,
areDeclarationAndDefinitionSame
).map(signatureByDescriptor))
}
}
}
@@ -88,7 +89,7 @@ object BuiltinSpecialBridgesUtil {
val superImplementationDescriptor =
if (specialBridge != null && fake && !functionHandle.isAbstract)
findSuperImplementationForStubDelegation(function, isBodyOwner, signatureByDescriptor)
findSuperImplementationForStubDelegation(function, areDeclarationAndDefinitionSame, signatureByDescriptor)
else
null
@@ -137,11 +138,11 @@ object BuiltinSpecialBridgesUtil {
* Also note that there is no special bridges for final declarations, thus no stubs either
*/
private fun <Signature> findSuperImplementationForStubDelegation(
function: FunctionDescriptor,
isBodyOwner: (DeclarationDescriptor) -> Boolean,
signatureByDescriptor: (FunctionDescriptor) -> Signature
function: FunctionDescriptor,
areDeclarationAndDefinitionSame: (CallableMemberDescriptor) -> Boolean,
signatureByDescriptor: (FunctionDescriptor) -> Signature
): FunctionDescriptor? {
val implementation = findConcreteSuperDeclaration(DescriptorBasedFunctionHandle(function, isBodyOwner)).descriptor
val implementation = findConcreteSuperDeclaration(DescriptorBasedFunctionHandle(function, areDeclarationAndDefinitionSame)).descriptor
// Implementation from interface will be generated by common mechanism
if (DescriptorUtils.isInterface(implementation.containingDeclaration)) return null
@@ -157,10 +158,15 @@ private fun <Signature> findSuperImplementationForStubDelegation(
}
private fun findAllReachableDeclarations(
functionDescriptor: FunctionDescriptor,
isBodyOwner: (DeclarationDescriptor) -> Boolean
functionDescriptor: FunctionDescriptor,
areDeclarationAndDefinitionSame: (CallableMemberDescriptor) -> Boolean
): MutableSet<FunctionDescriptor> =
findAllReachableDeclarations(DescriptorBasedFunctionHandle(functionDescriptor, isBodyOwner)).map { it.descriptor }.toMutableSet()
findAllReachableDeclarations(
DescriptorBasedFunctionHandle(
functionDescriptor,
areDeclarationAndDefinitionSame
)
).map { it.descriptor }.toMutableSet()
private fun <Signature> CallableMemberDescriptor.getSpecialBridgeSignatureIfExists(
signatureByDescriptor: (FunctionDescriptor) -> Signature