From b4ae70139ad4cf4849118162729f4a1f13105afd Mon Sep 17 00:00:00 2001 From: Michael Bogdanov Date: Fri, 19 Aug 2016 14:27:33 +0300 Subject: [PATCH] PropertyReferenceCodegen refactoring --- .../kotlin/codegen/ExpressionCodegen.java | 7 +- .../codegen/PropertyReferenceCodegen.kt | 140 ++++++++++-------- 2 files changed, 79 insertions(+), 68 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 7b23aa298a8..5a82cdfb8bc 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -3274,7 +3274,7 @@ public class ExpressionCodegen extends KtVisitor impleme if (variableDescriptor != null) { return generatePropertyReference( expression, variableDescriptor, (VariableDescriptor) resolvedCall.getResultingDescriptor(), - resolvedCall.getDispatchReceiver(), receiverAsmType, receiverValue + receiverAsmType, receiverValue ); } @@ -3286,7 +3286,6 @@ public class ExpressionCodegen extends KtVisitor impleme @NotNull KtElement element, @NotNull VariableDescriptor variableDescriptor, @NotNull VariableDescriptor target, - @Nullable ReceiverValue dispatchReceiver, @Nullable final Type receiverAsmType, @Nullable final StackValue receiverValue ) { @@ -3300,7 +3299,7 @@ public class ExpressionCodegen extends KtVisitor impleme PropertyReferenceCodegen codegen = new PropertyReferenceCodegen( state, parentCodegen, context.intoAnonymousClass(classDescriptor, this, OwnerKind.IMPLEMENTATION), - element, classBuilder, variableDescriptor, target, dispatchReceiver, receiverAsmType + element, classBuilder, variableDescriptor, target, receiverAsmType ); codegen.generate(); @@ -3960,7 +3959,7 @@ public class ExpressionCodegen extends KtVisitor impleme @NotNull StackValue metadataVar ) { //noinspection ConstantConditions - StackValue value = generatePropertyReference(variable.getDelegate(), variableDescriptor, variableDescriptor, null, null, null); + StackValue value = generatePropertyReference(variable.getDelegate(), variableDescriptor, variableDescriptor, null, null); value.put(K_PROPERTY0_TYPE, v); metadataVar.storeSelector(K_PROPERTY0_TYPE, v); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt index 588ca8af6ef..9b83cda0673 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt @@ -24,17 +24,17 @@ import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor -import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl +import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.resolve.DescriptorFactory import org.jetbrains.kotlin.resolve.PropertyImportedFromObject -import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.resolve.jvm.AsmTypes.* import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin -import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.utils.sure import org.jetbrains.org.objectweb.asm.Opcodes.* import org.jetbrains.org.objectweb.asm.Type @@ -49,25 +49,24 @@ class PropertyReferenceCodegen( classBuilder: ClassBuilder, private val localVariableDescriptorForReference: VariableDescriptor, private val target: VariableDescriptor, - dispatchReceiver: ReceiverValue?, - private val receiverType: Type? // non-null for bound references + private val receiverType: Type? ) : MemberCodegen(state, parentCodegen, context, expression, classBuilder) { private val classDescriptor = context.contextDescriptor private val asmType = typeMapper.mapClass(classDescriptor) - private val dispatchReceiverType = dispatchReceiver?.type - private val extensionReceiverType = target.extensionReceiverParameter?.type - - private val receiverCount = - (if (dispatchReceiverType != null) 1 else 0) + - (if (extensionReceiverType != null) 1 else 0) - - (if (receiverType != null) 1 else 0) - // e.g. MutablePropertyReference0 private val superAsmType = typeMapper.mapClass(classDescriptor.getSuperClassNotAny().sure { "No super class for $classDescriptor" }) + private val isLocalDelegatedProperty = target is LocalVariableDescriptor + + val getFunction = + if (isLocalDelegatedProperty) + (localVariableDescriptorForReference as VariableDescriptorWithAccessors).getter!! + else + findGetFunction(localVariableDescriptorForReference).original + // e.g. mutableProperty0(Lkotlin/jvm/internal/MutablePropertyReference0;)Lkotlin/reflect/KMutableProperty0; - private val wrapperMethod = getWrapperMethodForPropertyReference(target, receiverCount) + private val wrapperMethod = getWrapperMethodForPropertyReference(target, getFunction.valueParameters.size) private val closure = bindingContext.get(CodegenBinding.CLOSURE, classDescriptor)!!.apply { assert((captureReceiverType != null) == (receiverType != null)) { @@ -114,7 +113,7 @@ class PropertyReferenceCodegen( aconst(getPropertyReferenceSignature(target as VariableDescriptorWithAccessors, state)) } - if (target !is LocalVariableDescriptor) { + if (!isLocalDelegatedProperty) { generateMethod("property reference getOwner", ACC_PUBLIC, method("getOwner", K_DECLARATION_CONTAINER_TYPE)) { ClosureCodegen.generateCallableReferenceDeclarationContainer(this, target, state) } @@ -135,59 +134,18 @@ class PropertyReferenceCodegen( } private fun generateAccessors() { - fun generateAccessor(method: Method, accessorBody: InstructionAdapter.(StackValue) -> Unit) { - generateMethod("property reference $method", ACC_PUBLIC, method) { - // Note: this descriptor is an inaccurate representation of the get/set method. In particular, it has incorrect - // return type and value parameter types. However, it's created only to be able to use - // ExpressionCodegen#intermediateValueForProperty, which is poorly coupled with everything else. - val fakeDescriptor = SimpleFunctionDescriptorImpl.create( - classDescriptor, Annotations.EMPTY, Name.identifier(method.name), CallableMemberDescriptor.Kind.DECLARATION, - SourceElement.NO_SOURCE - ) - fakeDescriptor.initialize(null, classDescriptor.thisAsReceiverParameter, emptyList(), emptyList(), - classDescriptor.builtIns.anyType, Modality.OPEN, Visibilities.PUBLIC) - - val fakeCodegen = ExpressionCodegen( - this, FrameMap(), OBJECT_TYPE, context.intoFunction(fakeDescriptor), state, this@PropertyReferenceCodegen - ) - if (target is PropertyImportedFromObject) { - val containingObject = target.containingObject - StackValue.singleton(containingObject, typeMapper).put(typeMapper.mapClass(containingObject), this) - } - - if (receiverType != null) { - StackValue.field(receiverType, asmType, AsmUtil.CAPTURED_RECEIVER_FIELD, /* isStatic = */ false, StackValue.LOCAL_0) - .put(receiverType, this) - } - else { - for ((index, type) in listOfNotNull(dispatchReceiverType, extensionReceiverType).withIndex()) { - StackValue.local(index + 1, OBJECT_TYPE).put(typeMapper.mapType(type), this) - } - } - - val value = if (target is LocalVariableDescriptor) { - fakeCodegen.findLocalOrCapturedValue(target)!! - } - else fakeCodegen.intermediateValueForProperty(target as PropertyDescriptor, false, null, StackValue.none()) - - accessorBody(value) - } - } - - val getterParameters = (1..receiverCount).map { OBJECT_TYPE }.toTypedArray() - generateAccessor(method("get", OBJECT_TYPE, *getterParameters)) { value -> - value.put(OBJECT_TYPE, this) - } + val getFunction = findGetFunction(localVariableDescriptorForReference) + val getImpl = createFakeOpenDescriptor(getFunction, classDescriptor) + functionCodegen.generateMethod(JvmDeclarationOrigin.NO_ORIGIN, getImpl, PropertyReferenceGenerationStrategy(true, getFunction, target, asmType, receiverType, state)) if (!ReflectionTypes.isNumberedKMutablePropertyType(localVariableDescriptorForReference.type)) return - - val setterParameters = (getterParameters + arrayOf(OBJECT_TYPE)) - generateAccessor(method("set", Type.VOID_TYPE, *setterParameters)) { value -> - // Number of receivers (not size) is safe here because there's only java/lang/Object in the signature, no double/long parameters - value.store(StackValue.local(receiverCount + 1, OBJECT_TYPE), this) - } + val setFunction = localVariableDescriptorForReference.type.memberScope.getContributedFunctions(OperatorNameConventions.SET, NoLookupLocation.FROM_BACKEND).single() + val setImpl = createFakeOpenDescriptor(setFunction, classDescriptor) + functionCodegen.generateMethod(JvmDeclarationOrigin.NO_ORIGIN, setImpl, PropertyReferenceGenerationStrategy(false, setFunction, target, asmType, receiverType, state)) } + + private fun generateMethod(debugString: String, access: Int, method: Method, generate: InstructionAdapter.() -> Unit) { val mv = v.newMethod(JvmDeclarationOrigin.NO_ORIGIN, access, method.name, method.descriptor, null, null) @@ -249,5 +207,59 @@ class PropertyReferenceCodegen( } } } + + @JvmStatic + fun createFakeOpenDescriptor(getFunction: FunctionDescriptor, classDescriptor: ClassDescriptor): FunctionDescriptor { + return getFunction.original.copy(classDescriptor, Modality.OPEN, getFunction.visibility, getFunction.kind, false) + } + + @JvmStatic + fun findGetFunction(localVariableDescriptorForReference: VariableDescriptor) = localVariableDescriptorForReference.type.memberScope.getContributedFunctions(OperatorNameConventions.GET, NoLookupLocation.FROM_BACKEND).single() + } + + class PropertyReferenceGenerationStrategy( + val isGetter: Boolean, + val originalFunctionDesc: FunctionDescriptor, + val target: VariableDescriptor, + val asmType: Type, + val receiverType: Type?, + state: GenerationState + ) : + FunctionGenerationStrategy.CodegenBased(state) { + override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) { + val v = codegen.v + val typeMapper = state.typeMapper + if (target is PropertyImportedFromObject) { + val containingObject = target.containingObject + StackValue.singleton(containingObject, typeMapper).put(typeMapper.mapClass(containingObject), v) + } + + if (receiverType != null) { + StackValue.field(receiverType, asmType, AsmUtil.CAPTURED_RECEIVER_FIELD, /* isStatic = */ false, StackValue.LOCAL_0) + .put(receiverType, v) + } + else { + val receivers = originalFunctionDesc.valueParameters.dropLast(if (isGetter) 0 else 1) + receivers.forEachIndexed { i, valueParameterDescriptor -> + StackValue.local(i + 1, OBJECT_TYPE).put(typeMapper.mapType(valueParameterDescriptor), v) + } + } + + val value = if (target is LocalVariableDescriptor) { + codegen.findLocalOrCapturedValue(target)!! + } + else + codegen.intermediateValueForProperty(target as PropertyDescriptor, false, null, StackValue.none()) + + if (isGetter) { + value.put(OBJECT_TYPE, v) + } + else { + val functionDescriptor = codegen.context.functionDescriptor + value.store(StackValue.local(codegen.frameMap.getIndex(functionDescriptor.valueParameters.last()), OBJECT_TYPE), v) + } + v.areturn(signature.returnType) + } } } +