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