Refactor bridges generation for JVM
Make a separate subclass for DescriptorBasedFunctionHandle to allow customize the behavior without complex abstract concepts like `areDeclarationAndDefinitionSame`
This commit is contained in:
@@ -9,13 +9,11 @@ import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import kotlin.text.StringsKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
||||
import org.jetbrains.kotlin.backend.common.bridges.Bridge;
|
||||
import org.jetbrains.kotlin.backend.common.bridges.ImplKt;
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
|
||||
import org.jetbrains.kotlin.codegen.context.*;
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
||||
@@ -25,7 +23,6 @@ import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.codegen.state.TypeMapperUtilsKt;
|
||||
import org.jetbrains.kotlin.config.JvmDefaultMode;
|
||||
import org.jetbrains.kotlin.config.JvmTarget;
|
||||
import org.jetbrains.kotlin.config.LanguageFeature;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated;
|
||||
@@ -92,15 +89,6 @@ public class FunctionCodegen {
|
||||
private final ClassBuilder v;
|
||||
private final MemberCodegen<?> memberCodegen;
|
||||
|
||||
private final Function1<CallableMemberDescriptor, Boolean> DECLARATION_AND_DEFINITION_CHECKER = new Function1<CallableMemberDescriptor, Boolean>() {
|
||||
@Override
|
||||
public Boolean invoke(CallableMemberDescriptor descriptor) {
|
||||
return !isInterface(descriptor.getContainingDeclaration()) ||
|
||||
(state.getTarget() != JvmTarget.JVM_1_6 &&
|
||||
hasJvmDefaultAnnotation(descriptor));
|
||||
}
|
||||
};
|
||||
|
||||
public FunctionCodegen(
|
||||
@NotNull CodegenContext owner,
|
||||
@NotNull ClassBuilder v,
|
||||
@@ -1069,14 +1057,14 @@ public class FunctionCodegen {
|
||||
private boolean hasSpecialBridgeMethod(@NotNull FunctionDescriptor descriptor) {
|
||||
if (SpecialBuiltinMembers.getOverriddenBuiltinReflectingJvmDescriptor(descriptor) == null) return false;
|
||||
return !BuiltinSpecialBridgesUtil.generateBridgesForBuiltinSpecial(
|
||||
descriptor, typeMapper::mapAsmMethod, DECLARATION_AND_DEFINITION_CHECKER
|
||||
descriptor, typeMapper::mapAsmMethod, state.getTarget()
|
||||
).isEmpty();
|
||||
}
|
||||
|
||||
public void generateBridges(@NotNull FunctionDescriptor descriptor) {
|
||||
if (descriptor instanceof ConstructorDescriptor) return;
|
||||
if (owner.getContextKind() == OwnerKind.DEFAULT_IMPLS) return;
|
||||
if (!DECLARATION_AND_DEFINITION_CHECKER.invoke(descriptor)) return;
|
||||
if (JvmBridgesImplKt.isAbstractOnJvmIgnoringActualModality(state.getTarget(), descriptor)) return;
|
||||
|
||||
// equals(Any?), hashCode(), toString() never need bridges
|
||||
if (isMethodOfAny(descriptor)) return;
|
||||
@@ -1086,7 +1074,7 @@ public class FunctionCodegen {
|
||||
Set<Bridge<Method>> bridgesToGenerate;
|
||||
if (!isSpecial) {
|
||||
bridgesToGenerate =
|
||||
ImplKt.generateBridgesForFunctionDescriptor(descriptor, typeMapper::mapAsmMethod, DECLARATION_AND_DEFINITION_CHECKER);
|
||||
JvmBridgesImplKt.generateBridgesForFunctionDescriptorForJvm(descriptor, typeMapper::mapAsmMethod, state.getTarget());
|
||||
if (!bridgesToGenerate.isEmpty()) {
|
||||
PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null;
|
||||
boolean isSpecialBridge =
|
||||
@@ -1099,7 +1087,7 @@ public class FunctionCodegen {
|
||||
}
|
||||
else {
|
||||
Set<BridgeForBuiltinSpecial<Method>> specials = BuiltinSpecialBridgesUtil.generateBridgesForBuiltinSpecial(
|
||||
descriptor, typeMapper::mapAsmMethod, DECLARATION_AND_DEFINITION_CHECKER
|
||||
descriptor, typeMapper::mapAsmMethod, state.getTarget()
|
||||
);
|
||||
|
||||
if (!specials.isEmpty()) {
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.bridges.Bridge
|
||||
import org.jetbrains.kotlin.backend.common.bridges.DescriptorBasedFunctionHandle
|
||||
import org.jetbrains.kotlin.backend.common.bridges.generateBridges
|
||||
import org.jetbrains.kotlin.config.JvmTarget
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmDefaultAnnotation
|
||||
|
||||
class DescriptorBasedFunctionHandleForJvm(
|
||||
descriptor: FunctionDescriptor,
|
||||
private val jvmTarget: JvmTarget
|
||||
) : DescriptorBasedFunctionHandle(descriptor) {
|
||||
override fun createHandleForOverridden(overridden: FunctionDescriptor) =
|
||||
DescriptorBasedFunctionHandleForJvm(overridden, jvmTarget)
|
||||
|
||||
/*
|
||||
For @JvmDefault JVM members they are placed in interface classes and
|
||||
we need generate bridge for such function ('isAbstract' will return false).
|
||||
For non-@JvmDefault interfaces function, its body is generated in a separate place (DefaultImpls) and
|
||||
the method in the interface is abstract so we must not generate bridges for such cases.
|
||||
*/
|
||||
override val isAbstract: Boolean = super.isAbstract || isAbstractOnJvmIgnoringActualModality(jvmTarget, descriptor)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return return true for interface method not annotated with @JvmDefault
|
||||
*/
|
||||
fun isAbstractOnJvmIgnoringActualModality(jvmTarget: JvmTarget, descriptor: FunctionDescriptor): Boolean {
|
||||
if (!DescriptorUtils.isInterface(descriptor.containingDeclaration)) return false
|
||||
return jvmTarget == JvmTarget.JVM_1_6 || !descriptor.hasJvmDefaultAnnotation()
|
||||
}
|
||||
|
||||
fun <Signature> generateBridgesForFunctionDescriptorForJvm(
|
||||
descriptor: FunctionDescriptor,
|
||||
signature: (FunctionDescriptor) -> Signature,
|
||||
jvmTarget: JvmTarget
|
||||
): Set<Bridge<Signature>> {
|
||||
return generateBridges(DescriptorBasedFunctionHandleForJvm(descriptor, jvmTarget)) { signature(it.descriptor) }
|
||||
}
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
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.config.JvmTarget
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
@@ -47,14 +47,14 @@ object BuiltinSpecialBridgesUtil {
|
||||
fun <Signature : Any> generateBridgesForBuiltinSpecial(
|
||||
function: FunctionDescriptor,
|
||||
signatureByDescriptor: (FunctionDescriptor) -> Signature,
|
||||
areDeclarationAndDefinitionSame: (CallableMemberDescriptor) -> Boolean
|
||||
jvmTarget: JvmTarget
|
||||
): Set<BridgeForBuiltinSpecial<Signature>> {
|
||||
|
||||
val functionHandle = DescriptorBasedFunctionHandle(function, areDeclarationAndDefinitionSame)
|
||||
val functionHandle = DescriptorBasedFunctionHandleForJvm(function, jvmTarget)
|
||||
val fake = !functionHandle.isDeclaration
|
||||
val overriddenBuiltin = function.getOverriddenBuiltinReflectingJvmDescriptor()!!
|
||||
|
||||
val reachableDeclarations = findAllReachableDeclarations(function, areDeclarationAndDefinitionSame)
|
||||
val reachableDeclarations = findAllReachableDeclarations(function, jvmTarget)
|
||||
|
||||
// e.g. `getSize()I`
|
||||
val methodItself = signatureByDescriptor(function)
|
||||
@@ -78,11 +78,11 @@ object BuiltinSpecialBridgesUtil {
|
||||
|
||||
if (fake) {
|
||||
for (overridden in function.overriddenDescriptors.map { it.original }) {
|
||||
if (!DescriptorBasedFunctionHandle(overridden, areDeclarationAndDefinitionSame).isAbstract) {
|
||||
if (!DescriptorBasedFunctionHandleForJvm(overridden, jvmTarget).isAbstract) {
|
||||
commonBridges.removeAll(
|
||||
findAllReachableDeclarations(
|
||||
overridden,
|
||||
areDeclarationAndDefinitionSame
|
||||
jvmTarget
|
||||
).map(signatureByDescriptor)
|
||||
)
|
||||
}
|
||||
@@ -93,7 +93,7 @@ object BuiltinSpecialBridgesUtil {
|
||||
|
||||
val superImplementationDescriptor =
|
||||
if (specialBridge != null && fake && !functionHandle.isAbstract)
|
||||
findSuperImplementationForStubDelegation(function, areDeclarationAndDefinitionSame, signatureByDescriptor)
|
||||
findSuperImplementationForStubDelegation(function, jvmTarget, signatureByDescriptor)
|
||||
else
|
||||
null
|
||||
|
||||
@@ -150,10 +150,10 @@ object BuiltinSpecialBridgesUtil {
|
||||
*/
|
||||
private fun <Signature> findSuperImplementationForStubDelegation(
|
||||
function: FunctionDescriptor,
|
||||
areDeclarationAndDefinitionSame: (CallableMemberDescriptor) -> Boolean,
|
||||
jvmTarget: JvmTarget,
|
||||
signatureByDescriptor: (FunctionDescriptor) -> Signature
|
||||
): FunctionDescriptor? {
|
||||
val implementation = findConcreteSuperDeclaration(DescriptorBasedFunctionHandle(function, areDeclarationAndDefinitionSame))
|
||||
val implementation = findConcreteSuperDeclaration(DescriptorBasedFunctionHandleForJvm(function, jvmTarget))
|
||||
|
||||
// Implementation from interface will be generated by common mechanism
|
||||
if (!implementation.mayBeUsedAsSuperImplementation) return null
|
||||
@@ -170,12 +170,12 @@ private fun <Signature> findSuperImplementationForStubDelegation(
|
||||
|
||||
private fun findAllReachableDeclarations(
|
||||
functionDescriptor: FunctionDescriptor,
|
||||
areDeclarationAndDefinitionSame: (CallableMemberDescriptor) -> Boolean
|
||||
jvmTarget: JvmTarget
|
||||
): MutableSet<FunctionDescriptor> =
|
||||
findAllReachableDeclarations(
|
||||
DescriptorBasedFunctionHandle(
|
||||
DescriptorBasedFunctionHandleForJvm(
|
||||
functionDescriptor,
|
||||
areDeclarationAndDefinitionSame
|
||||
jvmTarget
|
||||
)
|
||||
).map { it.descriptor }.toMutableSet()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user