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 }