Optimize KProperty objects for delegated properties
Don't generate anonymous classes with a lot of methods because this hurts Android. Add special classes to the runtime instead (also add FunctionReferenceImpl, to be used later) and just create their instances in the static initializer of each class
This commit is contained in:
@@ -66,8 +66,7 @@ import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYN
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.VARIABLE;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isTopLevelDeclaration;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.PROPERTY_METADATA_TYPE;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt.Synthetic;
|
||||
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
|
||||
@@ -509,18 +508,41 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
|
||||
iv.newarray(PROPERTY_METADATA_TYPE);
|
||||
|
||||
for (int i = 0, size = delegatedProperties.size(); i < size; i++) {
|
||||
VariableDescriptor property = BindingContextUtils.getNotNull(bindingContext, VARIABLE, delegatedProperties.get(i));
|
||||
PropertyDescriptor property =
|
||||
(PropertyDescriptor) BindingContextUtils.getNotNull(bindingContext, VARIABLE, delegatedProperties.get(i));
|
||||
|
||||
iv.dup();
|
||||
iv.iconst(i);
|
||||
|
||||
ReceiverParameterDescriptor dispatchReceiver = property.getDispatchReceiverParameter();
|
||||
StackValue value;
|
||||
// TODO: remove this option and always generate PropertyReferenceNImpl creation
|
||||
if ("true".equalsIgnoreCase(System.getProperty("kotlin.jvm.optimize.delegated.properties"))) {
|
||||
int receiverCount = (property.getDispatchReceiverParameter() != null ? 1 : 0) +
|
||||
(property.getExtensionReceiverParameter() != null ? 1 : 0);
|
||||
Type implType = property.isVar() ? MUTABLE_PROPERTY_REFERENCE_IMPL[receiverCount] : PROPERTY_REFERENCE_IMPL[receiverCount];
|
||||
iv.anew(implType);
|
||||
iv.dup();
|
||||
// TODO: generate the container once and save to a local field instead
|
||||
ClosureCodegen.generateCallableReferenceDeclarationContainer(iv, property, state);
|
||||
iv.aconst(property.getName().asString());
|
||||
iv.aconst(PropertyReferenceCodegen.getPropertyReferenceSignature(property, state));
|
||||
iv.invokespecial(
|
||||
implType.getInternalName(), "<init>",
|
||||
Type.getMethodDescriptor(Type.VOID_TYPE, K_DECLARATION_CONTAINER_TYPE, JAVA_STRING_TYPE, JAVA_STRING_TYPE), false
|
||||
);
|
||||
value = StackValue.onStack(implType);
|
||||
Method wrapper = PropertyReferenceCodegen.getWrapperMethodForPropertyReference(property, receiverCount);
|
||||
iv.invokestatic(REFLECTION, wrapper.getName(), wrapper.getDescriptor(), false);
|
||||
}
|
||||
else {
|
||||
ReceiverParameterDescriptor dispatchReceiver = property.getDispatchReceiverParameter();
|
||||
|
||||
//noinspection ConstantConditions
|
||||
StackValue value = createOrGetClInitCodegen().generatePropertyReference(
|
||||
delegatedProperties.get(i).getDelegate(), property, property,
|
||||
dispatchReceiver != null ? new TransientReceiver(dispatchReceiver.getType()) : ReceiverValue.NO_RECEIVER
|
||||
);
|
||||
//noinspection ConstantConditions
|
||||
value = createOrGetClInitCodegen().generatePropertyReference(
|
||||
delegatedProperties.get(i).getDelegate(), property, property,
|
||||
dispatchReceiver != null ? new TransientReceiver(dispatchReceiver.getType()) : ReceiverValue.NO_RECEIVER
|
||||
);
|
||||
}
|
||||
|
||||
value.put(PROPERTY_METADATA_TYPE, iv);
|
||||
|
||||
|
||||
@@ -35,10 +35,7 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ScriptReceiver
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_FINAL
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_PUBLIC
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_SUPER
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.V1_6
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
@@ -74,24 +71,7 @@ public class PropertyReferenceCodegen(
|
||||
private val superAsmType = typeMapper.mapClass(classDescriptor.getSuperClassNotAny().sure { "No super class for $classDescriptor" })
|
||||
|
||||
// e.g. mutableProperty0(Lkotlin/jvm/internal/MutablePropertyReference0;)Lkotlin/reflect/KMutableProperty0;
|
||||
private val wrapperMethod: Method
|
||||
|
||||
init {
|
||||
wrapperMethod = when (receiverCount) {
|
||||
2 -> when {
|
||||
target.isVar -> method("mutableProperty2", K_MUTABLE_PROPERTY2_TYPE, MUTABLE_PROPERTY_REFERENCE2)
|
||||
else -> method("property2", K_PROPERTY2_TYPE, PROPERTY_REFERENCE2)
|
||||
}
|
||||
1 -> when {
|
||||
target.isVar -> method("mutableProperty1", K_MUTABLE_PROPERTY1_TYPE, MUTABLE_PROPERTY_REFERENCE1)
|
||||
else -> method("property1", K_PROPERTY1_TYPE, PROPERTY_REFERENCE1)
|
||||
}
|
||||
else -> when {
|
||||
target.isVar -> method("mutableProperty0", K_MUTABLE_PROPERTY0_TYPE, MUTABLE_PROPERTY_REFERENCE0)
|
||||
else -> method("property0", K_PROPERTY0_TYPE, PROPERTY_REFERENCE0)
|
||||
}
|
||||
}
|
||||
}
|
||||
private val wrapperMethod = getWrapperMethodForPropertyReference(target, receiverCount)
|
||||
|
||||
override fun generateDeclaration() {
|
||||
v.defineClass(
|
||||
@@ -127,16 +107,7 @@ public class PropertyReferenceCodegen(
|
||||
}
|
||||
|
||||
generateMethod("property reference getSignature", ACC_PUBLIC, method("getSignature", JAVA_STRING_TYPE)) {
|
||||
target as PropertyDescriptor
|
||||
|
||||
val getter = target.getGetter() ?: run {
|
||||
val defaultGetter = DescriptorFactory.createDefaultGetter(target, Annotations.EMPTY)
|
||||
defaultGetter.initialize(target.getType())
|
||||
defaultGetter
|
||||
}
|
||||
|
||||
val method = typeMapper.mapSignature(getter).getAsmMethod()
|
||||
aconst(method.getName() + method.getDescriptor())
|
||||
aconst(getPropertyReferenceSignature(target as PropertyDescriptor, state))
|
||||
}
|
||||
|
||||
generateAccessors()
|
||||
@@ -207,4 +178,35 @@ public class PropertyReferenceCodegen(
|
||||
StackValue.operation(wrapperMethod.getReturnType()) { iv ->
|
||||
iv.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, wrapperMethod.getReturnType().getDescriptor())
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getPropertyReferenceSignature(property: PropertyDescriptor, state: GenerationState): String {
|
||||
val getter =
|
||||
property.getter ?: DescriptorFactory.createDefaultGetter(property, Annotations.EMPTY).apply {
|
||||
initialize(property.type)
|
||||
}
|
||||
|
||||
val method = state.typeMapper.mapSignature(getter).asmMethod
|
||||
return method.name + method.descriptor
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getWrapperMethodForPropertyReference(property: VariableDescriptor, receiverCount: Int): Method {
|
||||
return when (receiverCount) {
|
||||
2 -> when {
|
||||
property.isVar -> method("mutableProperty2", K_MUTABLE_PROPERTY2_TYPE, MUTABLE_PROPERTY_REFERENCE2)
|
||||
else -> method("property2", K_PROPERTY2_TYPE, PROPERTY_REFERENCE2)
|
||||
}
|
||||
1 -> when {
|
||||
property.isVar -> method("mutableProperty1", K_MUTABLE_PROPERTY1_TYPE, MUTABLE_PROPERTY_REFERENCE1)
|
||||
else -> method("property1", K_PROPERTY1_TYPE, PROPERTY_REFERENCE1)
|
||||
}
|
||||
else -> when {
|
||||
property.isVar -> method("mutableProperty0", K_MUTABLE_PROPERTY0_TYPE, MUTABLE_PROPERTY_REFERENCE0)
|
||||
else -> method("property0", K_PROPERTY0_TYPE, PROPERTY_REFERENCE0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user