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