001    /*
002     * Copyright 2010-2016 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.codegen;
018    
019    import com.intellij.openapi.diagnostic.Logger;
020    import com.intellij.openapi.util.Pair;
021    import com.intellij.psi.PsiElement;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.kotlin.codegen.annotation.AnnotatedSimple;
025    import org.jetbrains.kotlin.codegen.annotation.AnnotatedWithFakeAnnotations;
026    import org.jetbrains.kotlin.codegen.context.*;
027    import org.jetbrains.kotlin.codegen.state.GenerationState;
028    import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
029    import org.jetbrains.kotlin.descriptors.*;
030    import org.jetbrains.kotlin.descriptors.annotations.Annotated;
031    import org.jetbrains.kotlin.descriptors.annotations.AnnotationSplitter;
032    import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget;
033    import org.jetbrains.kotlin.descriptors.annotations.Annotations;
034    import org.jetbrains.kotlin.load.java.JvmAbi;
035    import org.jetbrains.kotlin.psi.*;
036    import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
037    import org.jetbrains.kotlin.resolve.BindingContext;
038    import org.jetbrains.kotlin.resolve.DescriptorFactory;
039    import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
040    import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt;
041    import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
042    import org.jetbrains.kotlin.resolve.constants.ConstantValue;
043    import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
044    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
045    import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor;
046    import org.jetbrains.kotlin.storage.LockBasedStorageManager;
047    import org.jetbrains.kotlin.types.ErrorUtils;
048    import org.jetbrains.kotlin.types.KotlinType;
049    import org.jetbrains.org.objectweb.asm.FieldVisitor;
050    import org.jetbrains.org.objectweb.asm.MethodVisitor;
051    import org.jetbrains.org.objectweb.asm.Opcodes;
052    import org.jetbrains.org.objectweb.asm.Type;
053    import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
054    import org.jetbrains.org.objectweb.asm.commons.Method;
055    
056    import java.util.List;
057    
058    import static org.jetbrains.kotlin.codegen.AsmUtil.getDeprecatedAccessFlag;
059    import static org.jetbrains.kotlin.codegen.AsmUtil.getVisibilityForBackingField;
060    import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConstOrHasJvmFieldAnnotation;
061    import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface;
062    import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.FIELD_FOR_PROPERTY;
063    import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.SYNTHETIC_METHOD_FOR_PROPERTY;
064    import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
065    import static org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface;
066    import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.K_PROPERTY_TYPE;
067    import static org.jetbrains.kotlin.resolve.jvm.annotations.AnnotationUtilKt.hasJvmFieldAnnotation;
068    import static org.jetbrains.org.objectweb.asm.Opcodes.*;
069    
070    public class PropertyCodegen {
071    
072        private static Logger LOG = Logger.getInstance(PropertyCodegen.class);
073    
074        private final GenerationState state;
075        private final ClassBuilder v;
076        private final FunctionCodegen functionCodegen;
077        private final JetTypeMapper typeMapper;
078        private final BindingContext bindingContext;
079        private final FieldOwnerContext context;
080        private final MemberCodegen<?> memberCodegen;
081        private final OwnerKind kind;
082    
083        public PropertyCodegen(
084                @NotNull FieldOwnerContext context,
085                @NotNull ClassBuilder v,
086                @NotNull FunctionCodegen functionCodegen,
087                @NotNull MemberCodegen<?> memberCodegen
088        ) {
089            this.state = functionCodegen.state;
090            this.v = v;
091            this.functionCodegen = functionCodegen;
092            this.typeMapper = state.getTypeMapper();
093            this.bindingContext = state.getBindingContext();
094            this.context = context;
095            this.memberCodegen = memberCodegen;
096            this.kind = context.getContextKind();
097        }
098    
099        public void gen(@NotNull KtProperty property) {
100            VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, property);
101            if (!(variableDescriptor instanceof PropertyDescriptor)) {
102                throw ExceptionLogger.logDescriptorNotFound(
103                        "Property " + property.getName() + " should have a property descriptor: " + variableDescriptor, property
104                );
105            }
106    
107            PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor;
108            gen(property, propertyDescriptor, property.getGetter(), property.getSetter());
109        }
110    
111        public void generateInPackageFacade(@NotNull DeserializedPropertyDescriptor deserializedProperty) {
112            assert context instanceof MultifileClassFacadeContext : "should be called only for generating facade: " + context;
113            gen(null, deserializedProperty, null, null);
114        }
115    
116        private void gen(
117                @Nullable KtProperty declaration,
118                @NotNull PropertyDescriptor descriptor,
119                @Nullable KtPropertyAccessor getter,
120                @Nullable KtPropertyAccessor setter
121        ) {
122            assert kind == OwnerKind.PACKAGE || kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.DEFAULT_IMPLS
123                    : "Generating property with a wrong kind (" + kind + "): " + descriptor;
124    
125            if (isBackingFieldOwner(descriptor)) {
126                assert declaration != null : "Declaration is null for different context: " + context;
127    
128                genBackingFieldAndAnnotations(declaration, descriptor, false);
129            }
130    
131            if (isAccessorNeeded(declaration, descriptor, getter)) {
132                generateGetter(declaration, descriptor, getter);
133            }
134            if (isAccessorNeeded(declaration, descriptor, setter)) {
135                generateSetter(declaration, descriptor, setter);
136            }
137        }
138    
139        private boolean isBackingFieldOwner(@NotNull PropertyDescriptor descriptor) {
140            if (descriptor.isConst()) {
141                return !(context instanceof MultifileClassPartContext);
142            }
143            return CodegenContextUtil.isImplClassOwner(context);
144        }
145    
146        private void genBackingFieldAndAnnotations(@NotNull KtNamedDeclaration declaration, @NotNull PropertyDescriptor descriptor, boolean isParameter) {
147            boolean hasBackingField = hasBackingField(declaration, descriptor);
148            boolean hasDelegate = declaration instanceof KtProperty && ((KtProperty) declaration).hasDelegate();
149    
150            AnnotationSplitter annotationSplitter =
151                    AnnotationSplitter.create(LockBasedStorageManager.NO_LOCKS,
152                                              descriptor.getAnnotations(),
153                                              AnnotationSplitter.getTargetSet(isParameter, descriptor.isVar(), hasBackingField, hasDelegate));
154    
155            Annotations fieldAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.FIELD);
156            Annotations delegateAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD);
157            Annotations propertyAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY);
158    
159            generateBackingField(declaration, descriptor, fieldAnnotations, delegateAnnotations);
160            generateSyntheticMethodIfNeeded(descriptor, propertyAnnotations);
161        }
162    
163        /**
164         * Determines if it's necessary to generate an accessor to the property, i.e. if this property can be referenced via getter/setter
165         * for any reason
166         *
167         * @see JvmCodegenUtil#couldUseDirectAccessToProperty
168         */
169        private boolean isAccessorNeeded(
170                @Nullable KtProperty declaration,
171                @NotNull PropertyDescriptor descriptor,
172                @Nullable KtPropertyAccessor accessor
173        ) {
174            if (isConstOrHasJvmFieldAnnotation(descriptor)) return false;
175    
176            boolean isDefaultAccessor = accessor == null || !accessor.hasBody();
177    
178            // Don't generate accessors for interface properties with default accessors in DefaultImpls
179            if (kind == OwnerKind.DEFAULT_IMPLS && isDefaultAccessor) return false;
180    
181            if (declaration == null) return true;
182    
183            // Delegated or extension properties can only be referenced via accessors
184            if (declaration.hasDelegate() || declaration.getReceiverTypeReference() != null) return true;
185    
186            // Companion object properties always should have accessors, because their backing fields are moved/copied to the outer class
187            if (isCompanionObject(descriptor.getContainingDeclaration())) return true;
188    
189            // Private class properties have accessors only in cases when those accessors are non-trivial
190            if (Visibilities.isPrivate(descriptor.getVisibility())) {
191                return !isDefaultAccessor;
192            }
193    
194            return true;
195        }
196    
197        private static boolean areAccessorsNeededForPrimaryConstructorProperty(
198                @NotNull PropertyDescriptor descriptor
199        ) {
200            if (hasJvmFieldAnnotation(descriptor)) return false;
201    
202            return !Visibilities.isPrivate(descriptor.getVisibility());
203        }
204    
205        public void generatePrimaryConstructorProperty(@NotNull KtParameter p, @NotNull PropertyDescriptor descriptor) {
206            genBackingFieldAndAnnotations(p, descriptor, true);
207    
208            if (areAccessorsNeededForPrimaryConstructorProperty(descriptor)) {
209                generateGetter(p, descriptor, null);
210                generateSetter(p, descriptor, null);
211            }
212        }
213    
214        public void generateConstructorPropertyAsMethodForAnnotationClass(KtParameter p, PropertyDescriptor descriptor) {
215            JvmMethodSignature signature = typeMapper.mapAnnotationParameterSignature(descriptor);
216            String name = p.getName();
217            if (name == null) return;
218            MethodVisitor mv = v.newMethod(
219                    JvmDeclarationOriginKt.OtherOrigin(p, descriptor), ACC_PUBLIC | ACC_ABSTRACT, name,
220                    signature.getAsmMethod().getDescriptor(),
221                    signature.getGenericsSignature(),
222                    null
223            );
224    
225            KtExpression defaultValue = p.getDefaultValue();
226            if (defaultValue != null) {
227                ConstantValue<?> constant = ExpressionCodegen.getCompileTimeConstant(defaultValue, bindingContext);
228                assert state.getClassBuilderMode() != ClassBuilderMode.FULL || constant != null
229                        : "Default value for annotation parameter should be compile time value: " + defaultValue.getText();
230                if (constant != null) {
231                    AnnotationCodegen annotationCodegen = AnnotationCodegen.forAnnotationDefaultValue(mv, typeMapper);
232                    annotationCodegen.generateAnnotationDefaultValue(constant, descriptor.getType());
233                }
234            }
235    
236            mv.visitEnd();
237        }
238    
239        private boolean hasBackingField(@NotNull KtNamedDeclaration p, @NotNull PropertyDescriptor descriptor) {
240            return !isJvmInterface(descriptor.getContainingDeclaration()) &&
241                   kind != OwnerKind.DEFAULT_IMPLS &&
242                   !Boolean.FALSE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor));
243        }
244    
245        private boolean generateBackingField(
246                @NotNull KtNamedDeclaration p,
247                @NotNull PropertyDescriptor descriptor,
248                @NotNull Annotations backingFieldAnnotations,
249                @NotNull Annotations delegateAnnotations
250        ) {
251            if (isJvmInterface(descriptor.getContainingDeclaration()) || kind == OwnerKind.DEFAULT_IMPLS) {
252                return false;
253            }
254    
255            if (p instanceof KtProperty && ((KtProperty) p).hasDelegate()) {
256                generatePropertyDelegateAccess((KtProperty) p, descriptor, delegateAnnotations);
257            }
258            else if (Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor))) {
259                generateBackingFieldAccess(p, descriptor, backingFieldAnnotations);
260            }
261            else {
262                return false;
263            }
264            return true;
265        }
266    
267        // Annotations on properties are stored in bytecode on an empty synthetic method. This way they're still
268        // accessible via reflection, and 'deprecated' and 'private' flags prevent this method from being called accidentally
269        private void generateSyntheticMethodIfNeeded(@NotNull PropertyDescriptor descriptor, Annotations annotations) {
270            if (annotations.getAllAnnotations().isEmpty()) return;
271    
272            ReceiverParameterDescriptor receiver = descriptor.getExtensionReceiverParameter();
273            String name = JvmAbi.getSyntheticMethodNameForAnnotatedProperty(descriptor.getName());
274            String desc = receiver == null ? "()V" : "(" + typeMapper.mapType(receiver.getType()) + ")V";
275    
276            if (!isInterface(context.getContextDescriptor()) || kind == OwnerKind.DEFAULT_IMPLS) {
277                int flags = ACC_DEPRECATED | ACC_FINAL | ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC;
278                MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(descriptor), flags, name, desc, null, null);
279                AnnotationCodegen.forMethod(mv, typeMapper)
280                        .genAnnotations(new AnnotatedSimple(annotations), Type.VOID_TYPE, AnnotationUseSiteTarget.PROPERTY);
281                mv.visitCode();
282                mv.visitInsn(Opcodes.RETURN);
283                mv.visitEnd();
284            }
285    
286            if (kind != OwnerKind.DEFAULT_IMPLS) {
287                v.getSerializationBindings().put(SYNTHETIC_METHOD_FOR_PROPERTY, descriptor, new Method(name, desc));
288            }
289        }
290    
291        private void generateBackingField(
292                KtNamedDeclaration element,
293                PropertyDescriptor propertyDescriptor,
294                boolean isDelegate,
295                KotlinType jetType,
296                Object defaultValue,
297                Annotations annotations
298        ) {
299            int modifiers = getDeprecatedAccessFlag(propertyDescriptor);
300    
301            for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.FIELD_FLAGS) {
302                if (flagAnnotation.hasAnnotation(propertyDescriptor.getOriginal())) {
303                    modifiers |= flagAnnotation.getJvmFlag();
304                }
305            }
306    
307            if (kind == OwnerKind.PACKAGE) {
308                modifiers |= ACC_STATIC;
309            }
310    
311            if (!propertyDescriptor.isLateInit() && (!propertyDescriptor.isVar() || isDelegate)) {
312                modifiers |= ACC_FINAL;
313            }
314    
315            if (AnnotationUtilKt.hasJvmSyntheticAnnotation(propertyDescriptor)) {
316                modifiers |= ACC_SYNTHETIC;
317            }
318    
319            Type type = typeMapper.mapType(jetType);
320    
321            ClassBuilder builder = v;
322    
323            FieldOwnerContext backingFieldContext = context;
324            if (AsmUtil.isInstancePropertyWithStaticBackingField(propertyDescriptor) ) {
325                modifiers |= ACC_STATIC;
326    
327                if (JvmAbi.isPropertyWithBackingFieldInOuterClass(propertyDescriptor)) {
328                    ImplementationBodyCodegen codegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen();
329                    builder = codegen.v;
330                    backingFieldContext = codegen.context;
331                }
332            }
333            modifiers |= getVisibilityForBackingField(propertyDescriptor, isDelegate);
334    
335            if (AsmUtil.isPropertyWithBackingFieldCopyInOuterClass(propertyDescriptor)) {
336                ImplementationBodyCodegen parentBodyCodegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen();
337                parentBodyCodegen.addCompanionObjectPropertyToCopy(propertyDescriptor, defaultValue);
338            }
339    
340            String name = backingFieldContext.getFieldName(propertyDescriptor, isDelegate);
341    
342            v.getSerializationBindings().put(FIELD_FOR_PROPERTY, propertyDescriptor, Pair.create(type, name));
343    
344            FieldVisitor fv = builder.newField(JvmDeclarationOriginKt.OtherOrigin(element, propertyDescriptor), modifiers, name, type.getDescriptor(),
345                                               typeMapper.mapFieldSignature(jetType, propertyDescriptor), defaultValue);
346    
347            Annotated fieldAnnotated = new AnnotatedWithFakeAnnotations(propertyDescriptor, annotations);
348            AnnotationCodegen.forField(fv, typeMapper).genAnnotations(
349                    fieldAnnotated, type, isDelegate ? AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD : AnnotationUseSiteTarget.FIELD);
350        }
351    
352        private void generatePropertyDelegateAccess(KtProperty p, PropertyDescriptor propertyDescriptor, Annotations annotations) {
353            KtExpression delegateExpression = p.getDelegateExpression();
354            KotlinType delegateType = delegateExpression != null ? bindingContext.getType(p.getDelegateExpression()) : null;
355            if (delegateType == null) {
356                // If delegate expression is unresolved reference
357                delegateType = ErrorUtils.createErrorType("Delegate type");
358            }
359    
360            generateBackingField(p, propertyDescriptor, true, delegateType, null, annotations);
361        }
362    
363        private void generateBackingFieldAccess(KtNamedDeclaration p, PropertyDescriptor propertyDescriptor, Annotations annotations) {
364            Object value = null;
365    
366            if (shouldWriteFieldInitializer(propertyDescriptor)) {
367                ConstantValue<?> initializer = propertyDescriptor.getCompileTimeInitializer();
368                if (initializer != null) {
369                    value = initializer.getValue();
370                }
371            }
372    
373            generateBackingField(p, propertyDescriptor, false, propertyDescriptor.getType(), value, annotations);
374        }
375    
376        private boolean shouldWriteFieldInitializer(@NotNull PropertyDescriptor descriptor) {
377            //final field of primitive or String type
378            if (!descriptor.isVar()) {
379                Type type = typeMapper.mapType(descriptor);
380                return AsmUtil.isPrimitive(type) || "java.lang.String".equals(type.getClassName());
381            }
382            return false;
383        }
384    
385        private void generateGetter(@Nullable KtNamedDeclaration p, @NotNull PropertyDescriptor descriptor, @Nullable KtPropertyAccessor getter) {
386            generateAccessor(p, getter, descriptor.getGetter() != null
387                                        ? descriptor.getGetter()
388                                        : DescriptorFactory.createDefaultGetter(descriptor, Annotations.Companion.getEMPTY()));
389        }
390    
391        private void generateSetter(@Nullable KtNamedDeclaration p, @NotNull PropertyDescriptor descriptor, @Nullable KtPropertyAccessor setter) {
392            if (!descriptor.isVar()) return;
393    
394            generateAccessor(p, setter, descriptor.getSetter() != null
395                                        ? descriptor.getSetter()
396                                        : DescriptorFactory.createDefaultSetter(descriptor, Annotations.Companion.getEMPTY()));
397        }
398    
399        private void generateAccessor(
400                @Nullable KtNamedDeclaration p,
401                @Nullable KtPropertyAccessor accessor,
402                @NotNull PropertyAccessorDescriptor accessorDescriptor
403        ) {
404            if (context instanceof MultifileClassFacadeContext && Visibilities.isPrivate(accessorDescriptor.getVisibility())) {
405                return;
406            }
407    
408            FunctionGenerationStrategy strategy;
409            if (accessor == null || !accessor.hasBody()) {
410                if (p instanceof KtProperty && ((KtProperty) p).hasDelegate()) {
411                    strategy = new DelegatedPropertyAccessorStrategy(state, accessorDescriptor, indexOfDelegatedProperty((KtProperty) p));
412                }
413                else {
414                    strategy = new DefaultPropertyAccessorStrategy(state, accessorDescriptor);
415                }
416            }
417            else {
418                strategy = new FunctionGenerationStrategy.FunctionDefault(state, accessorDescriptor, accessor);
419            }
420    
421            functionCodegen.generateMethod(JvmDeclarationOriginKt.OtherOrigin(accessor != null ? accessor : p, accessorDescriptor), accessorDescriptor, strategy);
422        }
423    
424        public static int indexOfDelegatedProperty(@NotNull KtProperty property) {
425            PsiElement parent = property.getParent();
426            KtDeclarationContainer container;
427            if (parent instanceof KtClassBody) {
428                container = ((KtClassOrObject) parent.getParent());
429            }
430            else if (parent instanceof KtFile) {
431                container = (KtFile) parent;
432            }
433            else {
434                throw new UnsupportedOperationException("Unknown delegated property container: " + parent);
435            }
436    
437            int index = 0;
438            for (KtDeclaration declaration : container.getDeclarations()) {
439                if (declaration instanceof KtProperty && ((KtProperty) declaration).hasDelegate()) {
440                    if (declaration == property) {
441                        return index;
442                    }
443                    index++;
444                }
445            }
446    
447            throw new IllegalStateException("Delegated property not found in its parent: " + PsiUtilsKt.getElementTextWithContext(property));
448        }
449    
450    
451        private static class DefaultPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> {
452            public DefaultPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) {
453                super(state, descriptor);
454            }
455    
456            @Override
457            public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
458                InstructionAdapter v = codegen.v;
459                PropertyDescriptor propertyDescriptor = callableDescriptor.getCorrespondingProperty();
460                StackValue property = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0);
461    
462                PsiElement jetProperty = DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor);
463                if (jetProperty instanceof KtProperty || jetProperty instanceof KtParameter) {
464                    codegen.markLineNumber((KtElement) jetProperty, false);
465                }
466    
467                if (callableDescriptor instanceof PropertyGetterDescriptor) {
468                    Type type = signature.getReturnType();
469                    property.put(type, v);
470                    v.areturn(type);
471                }
472                else if (callableDescriptor instanceof PropertySetterDescriptor) {
473                    List<ValueParameterDescriptor> valueParameters = callableDescriptor.getValueParameters();
474                    assert valueParameters.size() == 1 : "Property setter should have only one value parameter but has " + callableDescriptor;
475                    int parameterIndex = codegen.lookupLocalIndex(valueParameters.get(0));
476                    assert parameterIndex >= 0 : "Local index for setter parameter should be positive or zero: " + callableDescriptor;
477                    Type type = codegen.typeMapper.mapType(propertyDescriptor);
478                    property.store(StackValue.local(parameterIndex, type), codegen.v);
479                    v.visitInsn(RETURN);
480                }
481                else {
482                    throw new IllegalStateException("Unknown property accessor: " + callableDescriptor);
483                }
484            }
485        }
486    
487        public static StackValue invokeDelegatedPropertyConventionMethod(
488                @NotNull PropertyDescriptor propertyDescriptor,
489                @NotNull ExpressionCodegen codegen,
490                @NotNull JetTypeMapper typeMapper,
491                @NotNull ResolvedCall<FunctionDescriptor> resolvedCall,
492                final int indexInPropertyMetadataArray,
493                int propertyMetadataArgumentIndex
494        ) {
495            CodegenContext<? extends ClassOrPackageFragmentDescriptor> ownerContext = codegen.getContext().getClassOrPackageParentContext();
496            final Type owner;
497            if (ownerContext instanceof ClassContext) {
498                owner = typeMapper.mapClass(((ClassContext) ownerContext).getContextDescriptor());
499            }
500            else if (ownerContext instanceof PackageContext) {
501                owner = ((PackageContext) ownerContext).getPackagePartType();
502            }
503            else if (ownerContext instanceof MultifileClassContextBase) {
504                owner = ((MultifileClassContextBase) ownerContext).getFilePartType();
505            }
506            else {
507                throw new UnsupportedOperationException("Unknown context: " + ownerContext);
508            }
509    
510            codegen.tempVariables.put(
511                    resolvedCall.getCall().getValueArguments().get(propertyMetadataArgumentIndex).asElement(),
512                    new StackValue(K_PROPERTY_TYPE) {
513                        @Override
514                        public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
515                            Field array = StackValue.field(
516                                    Type.getType("[" + K_PROPERTY_TYPE), owner, JvmAbi.DELEGATED_PROPERTIES_ARRAY_NAME, true, StackValue.none()
517                            );
518                            StackValue.arrayElement(
519                                    K_PROPERTY_TYPE, array, StackValue.constant(indexInPropertyMetadataArray, Type.INT_TYPE)
520                            ).put(type, v);
521                        }
522                    }
523            );
524    
525            StackValue delegatedProperty = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0);
526            return codegen.invokeFunction(resolvedCall, delegatedProperty);
527        }
528    
529        private static class DelegatedPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> {
530            private final int index;
531    
532            public DelegatedPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor, int index) {
533                super(state, descriptor);
534                this.index = index;
535            }
536    
537            @Override
538            public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
539                InstructionAdapter v = codegen.v;
540    
541                BindingContext bindingContext = state.getBindingContext();
542                ResolvedCall<FunctionDescriptor> resolvedCall =
543                        bindingContext.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, callableDescriptor);
544                assert resolvedCall != null : "Resolve call should be recorded for delegate call " + signature.toString();
545    
546                StackValue lastValue = invokeDelegatedPropertyConventionMethod(callableDescriptor.getCorrespondingProperty(),
547                                                                               codegen, state.getTypeMapper(), resolvedCall, index, 1);
548                Type asmType = signature.getReturnType();
549                lastValue.put(asmType, v);
550                v.areturn(asmType);
551            }
552        }
553    
554        public void genDelegate(@NotNull PropertyDescriptor delegate, @NotNull PropertyDescriptor delegateTo, @NotNull StackValue field) {
555            ClassDescriptor toClass = (ClassDescriptor) delegateTo.getContainingDeclaration();
556    
557            PropertyGetterDescriptor getter = delegate.getGetter();
558            if (getter != null) {
559                //noinspection ConstantConditions
560                functionCodegen.genDelegate(getter, delegateTo.getGetter().getOriginal(), toClass, field);
561            }
562    
563            PropertySetterDescriptor setter = delegate.getSetter();
564            if (setter != null) {
565                //noinspection ConstantConditions
566                functionCodegen.genDelegate(setter, delegateTo.getSetter().getOriginal(), toClass, field);
567            }
568        }
569    }