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