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