Optimize runtime representation for callable reference subclasses
Instead of generating overrides for getOwner/getName/getSignature in each anonymous class representing a callable reference, pass them to the superclass' constructor and store as fields. This occupies some small memory but helps to reduce the size of the generated class files, and will be helpful for adding further runtime information to callable references, such as information about implicit conversions this reference has been subject to. Represent owner as java.lang.Class + boolean instead of KDeclarationContainer, so that the unnecessary wrapping Class->KClass wouldn't happen before it's needed, and also to make sure all callable references remain serializable. Note that the argument type where the "is declaration container a class" is passed is int instead of boolean. The plan is to pass the aforementioned implicit conversion information as bits of this same integer value. #KT-27362 Fixed
This commit is contained in:
@@ -70,6 +70,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
protected final Type asmType;
|
||||
protected final int visibilityFlag;
|
||||
private final boolean shouldHaveBoundReferenceReceiver;
|
||||
private final boolean isOptimizedFunctionReference;
|
||||
|
||||
private Method constructor;
|
||||
protected Type superClassAsmType;
|
||||
@@ -119,6 +120,9 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
assert closure != null : "Closure must be calculated for class: " + classDescriptor;
|
||||
|
||||
this.shouldHaveBoundReferenceReceiver = CallableReferenceUtilKt.isForBoundCallableReference(closure);
|
||||
this.isOptimizedFunctionReference =
|
||||
functionReferenceTarget != null &&
|
||||
superClassType.getConstructor().getDeclarationDescriptor() == state.getJvmRuntimeTypes().getFunctionReferenceImpl();
|
||||
|
||||
this.asmType = typeMapper.mapClass(classDescriptor);
|
||||
|
||||
@@ -180,7 +184,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
protected void generateClosureBody() {
|
||||
functionCodegen.generateMethod(JvmDeclarationOriginKt.OtherOrigin(element, funDescriptor), funDescriptor, strategy);
|
||||
|
||||
if (functionReferenceTarget != null) {
|
||||
if (functionReferenceTarget != null && !isOptimizedFunctionReference) {
|
||||
generateFunctionReferenceMethods(functionReferenceTarget);
|
||||
}
|
||||
|
||||
@@ -285,7 +289,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
);
|
||||
}
|
||||
|
||||
protected void generateBridge(
|
||||
private void generateBridge(
|
||||
@NotNull Method bridge,
|
||||
@NotNull List<KotlinType> bridgeParameterKotlinTypes,
|
||||
@Nullable KotlinType bridgeReturnType,
|
||||
@@ -396,7 +400,8 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
}
|
||||
}
|
||||
|
||||
public static void generateCallableReferenceDeclarationContainer(
|
||||
// Returns false if null was generated.
|
||||
public static boolean generateCallableReferenceDeclarationContainerClass(
|
||||
@NotNull InstructionAdapter iv,
|
||||
@NotNull CallableDescriptor descriptor,
|
||||
@NotNull GenerationState state
|
||||
@@ -420,15 +425,20 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
}
|
||||
else {
|
||||
iv.aconst(null);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isContainerPackage =
|
||||
descriptor instanceof LocalVariableDescriptor
|
||||
? DescriptorUtils.getParentOfType(descriptor, ClassDescriptor.class) == null
|
||||
: container instanceof PackageFragmentDescriptor;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isContainerPackage) {
|
||||
public static void generateCallableReferenceDeclarationContainer(
|
||||
@NotNull InstructionAdapter iv,
|
||||
@NotNull CallableDescriptor descriptor,
|
||||
@NotNull GenerationState state
|
||||
) {
|
||||
if (!generateCallableReferenceDeclarationContainerClass(iv, descriptor, state)) return;
|
||||
|
||||
if (isTopLevelCallableReference(descriptor)) {
|
||||
// Note that this name is not used in reflection. There should be the name of the referenced declaration's module instead,
|
||||
// but there's no nice API to obtain that name here yet
|
||||
// TODO: write the referenced declaration's module name and use it in reflection
|
||||
@@ -441,6 +451,12 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isTopLevelCallableReference(@NotNull CallableDescriptor descriptor) {
|
||||
return descriptor instanceof LocalVariableDescriptor
|
||||
? DescriptorUtils.getParentOfType(descriptor, ClassDescriptor.class) == null
|
||||
: descriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected Method generateConstructor() {
|
||||
List<FieldInfo> args = calculateConstructorParameters(typeMapper, state.getLanguageVersionSettings(), closure, asmType);
|
||||
@@ -476,24 +492,38 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
|
||||
iv.load(0, superClassAsmType);
|
||||
|
||||
String superClassConstructorDescriptor;
|
||||
List<Type> superCtorArgTypes = new ArrayList<>();
|
||||
if (superClassAsmType.equals(LAMBDA) || superClassAsmType.equals(FUNCTION_REFERENCE) ||
|
||||
superClassAsmType.equals(FUNCTION_REFERENCE_IMPL) ||
|
||||
CoroutineCodegenUtilKt.isCoroutineSuperClass(state.getLanguageVersionSettings(), superClassAsmType.getInternalName())) {
|
||||
int arity = calculateArity();
|
||||
iv.iconst(arity);
|
||||
superCtorArgTypes.add(Type.INT_TYPE);
|
||||
if (shouldHaveBoundReferenceReceiver) {
|
||||
CallableReferenceUtilKt.loadBoundReferenceReceiverParameter(iv, boundReceiverParameterIndex, boundReceiverType, boundReceiverKotlinType);
|
||||
superClassConstructorDescriptor = "(ILjava/lang/Object;)V";
|
||||
CallableReferenceUtilKt.loadBoundReferenceReceiverParameter(
|
||||
iv, boundReceiverParameterIndex, boundReceiverType, boundReceiverKotlinType
|
||||
);
|
||||
superCtorArgTypes.add(OBJECT_TYPE);
|
||||
}
|
||||
else {
|
||||
superClassConstructorDescriptor = "(I)V";
|
||||
if (isOptimizedFunctionReference) {
|
||||
assert functionReferenceTarget != null : "No function reference target: " + funDescriptor;
|
||||
generateCallableReferenceDeclarationContainerClass(iv, functionReferenceTarget, state);
|
||||
iv.aconst(functionReferenceTarget.getName().asString());
|
||||
PropertyReferenceCodegen.generateCallableReferenceSignature(iv, functionReferenceTarget, state);
|
||||
iv.aconst(isTopLevelCallableReference(functionReferenceTarget) ? 1 : 0);
|
||||
superCtorArgTypes.add(JAVA_CLASS_TYPE);
|
||||
superCtorArgTypes.add(JAVA_STRING_TYPE);
|
||||
superCtorArgTypes.add(JAVA_STRING_TYPE);
|
||||
superCtorArgTypes.add(Type.INT_TYPE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert !shouldHaveBoundReferenceReceiver : "Unexpected bound reference with supertype " + superClassAsmType;
|
||||
superClassConstructorDescriptor = "()V";
|
||||
}
|
||||
iv.invokespecial(superClassAsmType.getInternalName(), "<init>", superClassConstructorDescriptor, false);
|
||||
iv.invokespecial(
|
||||
superClassAsmType.getInternalName(), "<init>",
|
||||
Type.getMethodDescriptor(Type.VOID_TYPE, superCtorArgTypes.toArray(new Type[0])), false
|
||||
);
|
||||
|
||||
iv.visitInsn(RETURN);
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.builtins.createFunctionType
|
||||
import org.jetbrains.kotlin.codegen.coroutines.coroutinesJvmInternalPackageFqName
|
||||
import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView
|
||||
import org.jetbrains.kotlin.codegen.coroutines.isSuspendLambdaOrLocalFunction
|
||||
import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.config.isReleaseCoroutines
|
||||
@@ -30,14 +31,22 @@ class JvmRuntimeTypes(module: ModuleDescriptor, private val languageVersionSetti
|
||||
private val kotlinCoroutinesJvmInternalPackage =
|
||||
MutablePackageFragmentDescriptor(module, languageVersionSettings.coroutinesJvmInternalPackageFqName())
|
||||
|
||||
val generateOptimizedCallableReferenceSuperClasses = languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4
|
||||
|
||||
private fun internal(className: String, packageFragment: PackageFragmentDescriptor = kotlinJvmInternalPackage): Lazy<ClassDescriptor> =
|
||||
lazy { createClass(packageFragment, className) }
|
||||
|
||||
private fun coroutinesInternal(name: String): Lazy<ClassDescriptor> =
|
||||
lazy { createCoroutineSuperClass(name) }
|
||||
|
||||
private fun propertyClasses(prefix: String, suffix: String): Lazy<List<ClassDescriptor>> =
|
||||
lazy { (0..2).map { i -> createClass(kotlinJvmInternalPackage, prefix + i + suffix) } }
|
||||
|
||||
private val lambda: ClassDescriptor by internal("Lambda")
|
||||
|
||||
private val functionReference: ClassDescriptor by internal("FunctionReference")
|
||||
val functionReferenceImpl: ClassDescriptor by internal("FunctionReferenceImpl")
|
||||
|
||||
private val localVariableReference: ClassDescriptor by internal("LocalVariableReference")
|
||||
private val mutableLocalVariableReference: ClassDescriptor by internal("MutableLocalVariableReference")
|
||||
|
||||
@@ -60,13 +69,10 @@ class JvmRuntimeTypes(module: ModuleDescriptor, private val languageVersionSetti
|
||||
coroutineImpl
|
||||
}
|
||||
|
||||
private val propertyReferences: List<ClassDescriptor> by lazy {
|
||||
(0..2).map { i -> createClass(kotlinJvmInternalPackage, "PropertyReference$i") }
|
||||
}
|
||||
|
||||
private val mutablePropertyReferences: List<ClassDescriptor> by lazy {
|
||||
(0..2).map { i -> createClass(kotlinJvmInternalPackage, "MutablePropertyReference$i") }
|
||||
}
|
||||
private val propertyReferences: List<ClassDescriptor> by propertyClasses("PropertyReference", "")
|
||||
private val mutablePropertyReferences: List<ClassDescriptor> by propertyClasses("MutablePropertyReference", "")
|
||||
private val propertyReferenceImpls: List<ClassDescriptor> by propertyClasses("PropertyReference", "Impl")
|
||||
private val mutablePropertyReferenceImpls: List<ClassDescriptor> by propertyClasses("MutablePropertyReference", "Impl")
|
||||
|
||||
private fun createClass(
|
||||
packageFragment: PackageFragmentDescriptor,
|
||||
@@ -144,7 +150,8 @@ class JvmRuntimeTypes(module: ModuleDescriptor, private val languageVersionSetti
|
||||
)
|
||||
|
||||
val suspendFunctionType = if (referencedFunction.isSuspend) suspendFunctionInterface?.defaultType else null
|
||||
return listOfNotNull(functionReference.defaultType, functionType, suspendFunctionType)
|
||||
val superClass = if (generateOptimizedCallableReferenceSuperClasses) functionReferenceImpl else functionReference
|
||||
return listOfNotNull(superClass.defaultType, functionType, suspendFunctionType)
|
||||
}
|
||||
|
||||
fun getSupertypeForPropertyReference(descriptor: VariableDescriptorWithAccessors, isMutable: Boolean, isBound: Boolean): KotlinType {
|
||||
@@ -157,6 +164,11 @@ class JvmRuntimeTypes(module: ModuleDescriptor, private val languageVersionSetti
|
||||
(if (descriptor.dispatchReceiverParameter != null) 1 else 0) -
|
||||
if (isBound) 1 else 0
|
||||
|
||||
return (if (isMutable) mutablePropertyReferences else propertyReferences)[arity].defaultType
|
||||
val classes = when {
|
||||
generateOptimizedCallableReferenceSuperClasses -> if (isMutable) mutablePropertyReferenceImpls else propertyReferenceImpls
|
||||
else -> if (isMutable) mutablePropertyReferences else propertyReferences
|
||||
}
|
||||
|
||||
return classes[arity].defaultType
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.codegen.inline.SourceMapper;
|
||||
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.ApiVersion;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotatedImpl;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
@@ -642,6 +643,8 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
|
||||
if (!state.getClassBuilderMode().generateBodies) return;
|
||||
|
||||
boolean generateClassIntCtorCall = state.getJvmRuntimeTypes().getGenerateOptimizedCallableReferenceSuperClasses();
|
||||
|
||||
InstructionAdapter iv = createOrGetClInitCodegen().v;
|
||||
iv.iconst(delegatedProperties.size());
|
||||
iv.newarray(K_PROPERTY_TYPE);
|
||||
@@ -658,14 +661,29 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
iv.anew(implType);
|
||||
iv.dup();
|
||||
|
||||
// TODO: generate the container once and save to a local field instead (KT-10495)
|
||||
ClosureCodegen.generateCallableReferenceDeclarationContainer(iv, property, state);
|
||||
List<Type> superCtorArgTypes = new ArrayList<>();
|
||||
if (generateClassIntCtorCall) {
|
||||
ClosureCodegen.generateCallableReferenceDeclarationContainerClass(iv, property, state);
|
||||
superCtorArgTypes.add(JAVA_CLASS_TYPE);
|
||||
} else {
|
||||
// TODO: generate the container once and save to a local field instead (KT-10495)
|
||||
ClosureCodegen.generateCallableReferenceDeclarationContainer(iv, property, state);
|
||||
superCtorArgTypes.add(K_DECLARATION_CONTAINER_TYPE);
|
||||
}
|
||||
|
||||
iv.aconst(property.getName().asString());
|
||||
PropertyReferenceCodegen.generateCallableReferenceSignature(iv, property, state);
|
||||
superCtorArgTypes.add(JAVA_STRING_TYPE);
|
||||
superCtorArgTypes.add(JAVA_STRING_TYPE);
|
||||
|
||||
if (generateClassIntCtorCall) {
|
||||
iv.aconst(ClosureCodegen.isTopLevelCallableReference(property) ? 1 : 0);
|
||||
superCtorArgTypes.add(Type.INT_TYPE);
|
||||
}
|
||||
|
||||
iv.invokespecial(
|
||||
implType.getInternalName(), "<init>",
|
||||
Type.getMethodDescriptor(Type.VOID_TYPE, K_DECLARATION_CONTAINER_TYPE, JAVA_STRING_TYPE, JAVA_STRING_TYPE), false
|
||||
Type.getMethodDescriptor(Type.VOID_TYPE, superCtorArgTypes.toArray(new Type[0])), false
|
||||
);
|
||||
Method wrapper = PropertyReferenceCodegen.getWrapperMethodForPropertyReference(property, receiverCount);
|
||||
iv.invokestatic(REFLECTION, wrapper.getName(), wrapper.getDescriptor(), false);
|
||||
|
||||
@@ -114,16 +114,16 @@ class PropertyReferenceCodegen(
|
||||
|
||||
generateConstructor()
|
||||
|
||||
generateMethod("property reference getName", ACC_PUBLIC, method("getName", JAVA_STRING_TYPE)) {
|
||||
aconst(target.name.asString())
|
||||
}
|
||||
|
||||
generateMethod("property reference getSignature", ACC_PUBLIC, method("getSignature", JAVA_STRING_TYPE)) {
|
||||
generateCallableReferenceSignature(this, target, state)
|
||||
}
|
||||
|
||||
generateMethod("property reference getOwner", ACC_PUBLIC, method("getOwner", K_DECLARATION_CONTAINER_TYPE)) {
|
||||
ClosureCodegen.generateCallableReferenceDeclarationContainer(this, target, state)
|
||||
if (!isOptimizedPropertyReferenceSupertype(superAsmType)) {
|
||||
generateMethod("property reference getName", ACC_PUBLIC, method("getName", JAVA_STRING_TYPE)) {
|
||||
aconst(target.name.asString())
|
||||
}
|
||||
generateMethod("property reference getSignature", ACC_PUBLIC, method("getSignature", JAVA_STRING_TYPE)) {
|
||||
generateCallableReferenceSignature(this, target, state)
|
||||
}
|
||||
generateMethod("property reference getOwner", ACC_PUBLIC, method("getOwner", K_DECLARATION_CONTAINER_TYPE)) {
|
||||
ClosureCodegen.generateCallableReferenceDeclarationContainer(this, target, state)
|
||||
}
|
||||
}
|
||||
|
||||
if (!isLocalDelegatedProperty) {
|
||||
@@ -136,16 +136,31 @@ class PropertyReferenceCodegen(
|
||||
val shouldHaveBoundReferenceReceiver = closure.isForBoundCallableReference()
|
||||
val receiverIndexAndFieldInfo = generateClosureFieldsInitializationFromParameters(closure, constructorArgs)
|
||||
|
||||
if (receiverIndexAndFieldInfo == null) {
|
||||
assert(!shouldHaveBoundReferenceReceiver) { "No bound reference receiver in constructor parameters: $constructorArgs" }
|
||||
load(0, OBJECT_TYPE)
|
||||
invokespecial(superAsmType.internalName, "<init>", "()V", false)
|
||||
} else {
|
||||
load(0, OBJECT_TYPE)
|
||||
val superCtorArgTypes = mutableListOf<Type>()
|
||||
if (receiverIndexAndFieldInfo != null) {
|
||||
val (receiverIndex, receiverFieldInfo) = receiverIndexAndFieldInfo
|
||||
load(0, OBJECT_TYPE)
|
||||
loadBoundReferenceReceiverParameter(receiverIndex, receiverFieldInfo.fieldType, receiverFieldInfo.fieldKotlinType)
|
||||
invokespecial(superAsmType.internalName, "<init>", "(Ljava/lang/Object;)V", false)
|
||||
superCtorArgTypes.add(OBJECT_TYPE)
|
||||
} else {
|
||||
assert(!shouldHaveBoundReferenceReceiver) { "No bound reference receiver in constructor parameters: $constructorArgs" }
|
||||
}
|
||||
|
||||
if (isOptimizedPropertyReferenceSupertype(superAsmType)) {
|
||||
ClosureCodegen.generateCallableReferenceDeclarationContainerClass(this, target, state)
|
||||
aconst(target.name.asString())
|
||||
generateCallableReferenceSignature(this, target, state)
|
||||
aconst(if (ClosureCodegen.isTopLevelCallableReference(target)) 1 else 0)
|
||||
superCtorArgTypes.add(JAVA_CLASS_TYPE)
|
||||
superCtorArgTypes.add(JAVA_STRING_TYPE)
|
||||
superCtorArgTypes.add(JAVA_STRING_TYPE)
|
||||
superCtorArgTypes.add(Type.INT_TYPE)
|
||||
}
|
||||
|
||||
invokespecial(
|
||||
superAsmType.internalName, "<init>",
|
||||
Type.getMethodDescriptor(Type.VOID_TYPE, *superCtorArgTypes.toTypedArray()), false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ abstract class DefaultLambda(
|
||||
interfaces: Array<out String>?
|
||||
) {
|
||||
isPropertyReference = superName in PROPERTY_REFERENCE_SUPER_CLASSES
|
||||
isFunctionReference = superName == FUNCTION_REFERENCE.internalName
|
||||
isFunctionReference = superName == FUNCTION_REFERENCE.internalName || superName == FUNCTION_REFERENCE_IMPL.internalName
|
||||
|
||||
super.visit(version, access, name, signature, superName, interfaces)
|
||||
}
|
||||
@@ -204,10 +204,12 @@ abstract class DefaultLambda(
|
||||
protected abstract fun mapAsmSignature(sourceCompiler: SourceCompilerForInline): Method
|
||||
|
||||
private companion object {
|
||||
val PROPERTY_REFERENCE_SUPER_CLASSES = listOf(
|
||||
PROPERTY_REFERENCE0, PROPERTY_REFERENCE1, PROPERTY_REFERENCE2,
|
||||
MUTABLE_PROPERTY_REFERENCE0, MUTABLE_PROPERTY_REFERENCE1, MUTABLE_PROPERTY_REFERENCE2
|
||||
).mapTo(HashSet(), Type::getInternalName)
|
||||
val PROPERTY_REFERENCE_SUPER_CLASSES =
|
||||
listOf(
|
||||
PROPERTY_REFERENCE0, PROPERTY_REFERENCE1, PROPERTY_REFERENCE2,
|
||||
MUTABLE_PROPERTY_REFERENCE0, MUTABLE_PROPERTY_REFERENCE1, MUTABLE_PROPERTY_REFERENCE2
|
||||
).plus(OPTIMIZED_PROPERTY_REFERENCE_SUPERTYPES)
|
||||
.mapTo(HashSet(), Type::getInternalName)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Generated
+15
@@ -1978,6 +1978,16 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/callableReference/nested.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("optimizedSuperclasses_after.kt")
|
||||
public void testOptimizedSuperclasses_after() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/optimizedSuperclasses_after.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("optimizedSuperclasses_before.kt")
|
||||
public void testOptimizedSuperclasses_before() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/optimizedSuperclasses_before.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/callableReference/bound")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@@ -8625,6 +8635,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/delegatedProperty"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeDeclarationContainerOptimization.kt")
|
||||
public void testBeforeDeclarationContainerOptimization() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/delegatedProperty/beforeDeclarationContainerOptimization.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("capturePropertyInClosure.kt")
|
||||
public void testCapturePropertyInClosure() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/delegatedProperty/capturePropertyInClosure.kt");
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.jvm;
|
||||
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
public class AsmTypes {
|
||||
private static final Map<Class<?>, Type> TYPES_MAP = new HashMap<>();
|
||||
@@ -29,7 +29,10 @@ public class AsmTypes {
|
||||
public static final Type UNIT_TYPE = Type.getObjectType("kotlin/Unit");
|
||||
|
||||
public static final Type LAMBDA = Type.getObjectType("kotlin/jvm/internal/Lambda");
|
||||
|
||||
public static final Type FUNCTION_REFERENCE = Type.getObjectType("kotlin/jvm/internal/FunctionReference");
|
||||
public static final Type FUNCTION_REFERENCE_IMPL = Type.getObjectType("kotlin/jvm/internal/FunctionReferenceImpl");
|
||||
|
||||
public static final Type PROPERTY_REFERENCE0 = Type.getObjectType("kotlin/jvm/internal/PropertyReference0");
|
||||
public static final Type PROPERTY_REFERENCE1 = Type.getObjectType("kotlin/jvm/internal/PropertyReference1");
|
||||
public static final Type PROPERTY_REFERENCE2 = Type.getObjectType("kotlin/jvm/internal/PropertyReference2");
|
||||
@@ -37,8 +40,6 @@ public class AsmTypes {
|
||||
public static final Type MUTABLE_PROPERTY_REFERENCE1 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference1");
|
||||
public static final Type MUTABLE_PROPERTY_REFERENCE2 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference2");
|
||||
|
||||
public static final Type RESULT_FAILURE = Type.getObjectType("kotlin/Result$Failure");
|
||||
|
||||
public static final Type FUNCTION0 = Type.getObjectType("kotlin/jvm/functions/Function0");
|
||||
public static final Type FUNCTION1 = Type.getObjectType("kotlin/jvm/functions/Function1");
|
||||
|
||||
@@ -124,6 +125,16 @@ public class AsmTypes {
|
||||
return TYPES_MAP.computeIfAbsent(javaClass, k -> Type.getType(javaClass));
|
||||
}
|
||||
|
||||
public static final List<Type> OPTIMIZED_PROPERTY_REFERENCE_SUPERTYPES =
|
||||
CollectionsKt.flatten(Arrays.asList(
|
||||
Arrays.asList(PROPERTY_REFERENCE_IMPL),
|
||||
Arrays.asList(MUTABLE_PROPERTY_REFERENCE_IMPL)
|
||||
));
|
||||
|
||||
public static boolean isOptimizedPropertyReferenceSupertype(@NotNull Type type) {
|
||||
return OPTIMIZED_PROPERTY_REFERENCE_SUPERTYPES.contains(type);
|
||||
}
|
||||
|
||||
private AsmTypes() {
|
||||
}
|
||||
}
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
|
||||
class A {
|
||||
fun memberFunction() {}
|
||||
val memberProperty: String = ""
|
||||
}
|
||||
|
||||
val topLevelProperty: Int = 0
|
||||
|
||||
fun check(reference: Any, expected: String, message: String) {
|
||||
val actual = reference.javaClass.declaredMethods.map { it.name }.sorted().toString()
|
||||
if (expected != actual) {
|
||||
throw AssertionError("Fail on $message. Expected: $expected. Actual: $actual")
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
check(A::memberFunction, "[invoke, invoke]", "unbound function reference")
|
||||
check(A()::memberFunction, "[invoke, invoke]", "bound function reference")
|
||||
|
||||
check(::topLevelProperty, "[get]", "unbound property reference 0")
|
||||
check(A::memberProperty, "[get]", "unbound property reference 1")
|
||||
check(A()::memberProperty, "[get]", "bound property reference 1")
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// !API_VERSION: 1.3
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
|
||||
class A {
|
||||
fun memberFunction() {}
|
||||
val memberProperty: String = ""
|
||||
}
|
||||
|
||||
val topLevelProperty: Int = 0
|
||||
|
||||
fun check(reference: Any, expected: String, message: String) {
|
||||
val actual = reference.javaClass.declaredMethods.map { it.name }.sorted().toString()
|
||||
if (expected != actual) {
|
||||
throw AssertionError("Fail on $message. Expected: $expected. Actual: $actual")
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
check(A::memberFunction, "[getName, getOwner, getSignature, invoke, invoke]", "unbound function reference")
|
||||
check(A()::memberFunction, "[getName, getOwner, getSignature, invoke, invoke]", "bound function reference")
|
||||
|
||||
check(::topLevelProperty, "[get, getName, getOwner, getSignature]", "unbound property reference 0")
|
||||
check(A::memberProperty, "[get, getName, getOwner, getSignature]", "unbound property reference 1")
|
||||
check(A()::memberProperty, "[get, getName, getOwner, getSignature]", "bound property reference 1")
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// !API_VERSION: 1.3
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
|
||||
// This test simply checks that we still generate correct calls to PropertyReference1Impl constructors for API version < 1.4,
|
||||
// where we added and started using new constructors which take j.l.Class+int instead of KDeclarationContainer.
|
||||
|
||||
class D(val v: String) {
|
||||
operator fun getValue(a: Any?, b: Any?): String = v
|
||||
operator fun setValue(a: Any?, b: Any?, c: String) {}
|
||||
}
|
||||
|
||||
class A {
|
||||
val o by D("O")
|
||||
var k by D("K")
|
||||
val z by D("")
|
||||
}
|
||||
|
||||
fun box(): String =
|
||||
A().o + A().k + A().z
|
||||
-12
@@ -12,9 +12,6 @@ synthetic final class NoReceiverInCallableReferenceClassesKt$A_bar$1 {
|
||||
static method <clinit>(): void
|
||||
method <init>(): void
|
||||
public @org.jetbrains.annotations.Nullable method get(@org.jetbrains.annotations.Nullable p0: java.lang.Object): java.lang.Object
|
||||
public method getName(): java.lang.String
|
||||
public method getOwner(): kotlin.reflect.KDeclarationContainer
|
||||
public method getSignature(): java.lang.String
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
@@ -23,9 +20,6 @@ synthetic final class NoReceiverInCallableReferenceClassesKt$A_foo$1 {
|
||||
inner class NoReceiverInCallableReferenceClassesKt$A_foo$1
|
||||
static method <clinit>(): void
|
||||
method <init>(): void
|
||||
public final method getName(): java.lang.String
|
||||
public final method getOwner(): kotlin.reflect.KDeclarationContainer
|
||||
public final method getSignature(): java.lang.String
|
||||
public final method invoke(@org.jetbrains.annotations.NotNull p0: A): void
|
||||
public synthetic bridge method invoke(p0: java.lang.Object): java.lang.Object
|
||||
}
|
||||
@@ -34,18 +28,12 @@ synthetic final class NoReceiverInCallableReferenceClassesKt$A_foo$1 {
|
||||
synthetic final class NoReceiverInCallableReferenceClassesKt$aBar$1 {
|
||||
method <init>(p0: A): void
|
||||
public @org.jetbrains.annotations.Nullable method get(): java.lang.Object
|
||||
public method getName(): java.lang.String
|
||||
public method getOwner(): kotlin.reflect.KDeclarationContainer
|
||||
public method getSignature(): java.lang.String
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
synthetic final class NoReceiverInCallableReferenceClassesKt$aFoo$1 {
|
||||
inner class NoReceiverInCallableReferenceClassesKt$aFoo$1
|
||||
method <init>(p0: A): void
|
||||
public final method getName(): java.lang.String
|
||||
public final method getOwner(): kotlin.reflect.KDeclarationContainer
|
||||
public final method getSignature(): java.lang.String
|
||||
public synthetic bridge method invoke(): java.lang.Object
|
||||
public final method invoke(): void
|
||||
}
|
||||
|
||||
@@ -8,18 +8,6 @@ class A {
|
||||
// TESTED_OBJECTS: A$bar$1
|
||||
// FLAGS: ACC_FINAL, ACC_SUPER, ACC_SYNTHETIC
|
||||
|
||||
// TESTED_OBJECT_KIND: function
|
||||
// TESTED_OBJECTS: A$bar$1, getName
|
||||
// FLAGS: ACC_PUBLIC, ACC_FINAL
|
||||
|
||||
// TESTED_OBJECT_KIND: function
|
||||
// TESTED_OBJECTS: A$bar$1, getOwner
|
||||
// FLAGS: ACC_PUBLIC, ACC_FINAL
|
||||
|
||||
// TESTED_OBJECT_KIND: function
|
||||
// TESTED_OBJECTS: A$bar$1, getSignature
|
||||
// FLAGS: ACC_PUBLIC, ACC_FINAL
|
||||
|
||||
// TESTED_OBJECT_KIND: function
|
||||
// TESTED_OBJECTS: A$bar$1, invoke
|
||||
// FLAGS: ACC_PUBLIC, ACC_FINAL
|
||||
// FLAGS: ACC_PUBLIC, ACC_FINAL
|
||||
|
||||
@@ -8,18 +8,6 @@ class A {
|
||||
// TESTED_OBJECTS: A$bar$1
|
||||
// FLAGS: ACC_FINAL, ACC_SUPER, ACC_SYNTHETIC
|
||||
|
||||
// TESTED_OBJECT_KIND: function
|
||||
// TESTED_OBJECTS: A$bar$1, getName
|
||||
// FLAGS: ACC_PUBLIC
|
||||
|
||||
// TESTED_OBJECT_KIND: function
|
||||
// TESTED_OBJECTS: A$bar$1, getOwner
|
||||
// FLAGS: ACC_PUBLIC
|
||||
|
||||
// TESTED_OBJECT_KIND: function
|
||||
// TESTED_OBJECTS: A$bar$1, getSignature
|
||||
// FLAGS: ACC_PUBLIC
|
||||
|
||||
// TESTED_OBJECT_KIND: function
|
||||
// TESTED_OBJECTS: A$bar$1, get
|
||||
// FLAGS: ACC_PUBLIC
|
||||
// FLAGS: ACC_PUBLIC
|
||||
|
||||
+15
@@ -1998,6 +1998,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/callableReference/nested.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("optimizedSuperclasses_after.kt")
|
||||
public void testOptimizedSuperclasses_after() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/optimizedSuperclasses_after.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("optimizedSuperclasses_before.kt")
|
||||
public void testOptimizedSuperclasses_before() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/optimizedSuperclasses_before.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/callableReference/bound")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@@ -9770,6 +9780,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/delegatedProperty"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeDeclarationContainerOptimization.kt")
|
||||
public void testBeforeDeclarationContainerOptimization() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/delegatedProperty/beforeDeclarationContainerOptimization.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("capturePropertyInClosure.kt")
|
||||
public void testCapturePropertyInClosure() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/delegatedProperty/capturePropertyInClosure.kt");
|
||||
|
||||
+15
@@ -1998,6 +1998,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/callableReference/nested.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("optimizedSuperclasses_after.kt")
|
||||
public void testOptimizedSuperclasses_after() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/optimizedSuperclasses_after.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("optimizedSuperclasses_before.kt")
|
||||
public void testOptimizedSuperclasses_before() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/optimizedSuperclasses_before.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/callableReference/bound")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@@ -9775,6 +9785,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/delegatedProperty"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeDeclarationContainerOptimization.kt")
|
||||
public void testBeforeDeclarationContainerOptimization() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/delegatedProperty/beforeDeclarationContainerOptimization.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("capturePropertyInClosure.kt")
|
||||
public void testCapturePropertyInClosure() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/delegatedProperty/capturePropertyInClosure.kt");
|
||||
|
||||
+15
@@ -1978,6 +1978,16 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/callableReference/nested.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("optimizedSuperclasses_after.kt")
|
||||
public void testOptimizedSuperclasses_after() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/optimizedSuperclasses_after.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("optimizedSuperclasses_before.kt")
|
||||
public void testOptimizedSuperclasses_before() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/callableReference/optimizedSuperclasses_before.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/callableReference/bound")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@@ -8625,6 +8635,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/delegatedProperty"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeDeclarationContainerOptimization.kt")
|
||||
public void testBeforeDeclarationContainerOptimization() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/delegatedProperty/beforeDeclarationContainerOptimization.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("capturePropertyInClosure.kt")
|
||||
public void testCapturePropertyInClosure() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/delegatedProperty/capturePropertyInClosure.kt");
|
||||
|
||||
Reference in New Issue
Block a user