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 if (AsmUtil.isInstancePropertyWithStaticBackingField(propertyDescriptor) ) {
304 modifiers |= ACC_STATIC;
305
306 if (propertyDescriptor.isLateInit()) {
307 modifiers |= getVisibilityAccessFlag(propertyDescriptor);
308 }
309 else if (hasPublicFieldAnnotation && !isDelegate) {
310 modifiers |= ACC_PUBLIC;
311 }
312 else {
313 modifiers |= getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegate);
314 }
315
316 if (AsmUtil.isPropertyWithBackingFieldInOuterClass(propertyDescriptor)) {
317 ImplementationBodyCodegen codegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen();
318 builder = codegen.v;
319 backingFieldContext = codegen.context;
320 v.getSerializationBindings().put(STATIC_FIELD_IN_OUTER_CLASS, propertyDescriptor);
321 }
322 }
323 else if (propertyDescriptor.isLateInit()) {
324 modifiers |= getVisibilityAccessFlag(propertyDescriptor);
325 }
326 else if (!isDelegate && hasPublicFieldAnnotation) {
327 modifiers |= ACC_PUBLIC;
328 }
329 else if (kind != OwnerKind.PACKAGE || isDelegate) {
330 modifiers |= ACC_PRIVATE;
331 }
332
333 if (AsmUtil.isPropertyWithBackingFieldCopyInOuterClass(propertyDescriptor)) {
334 ImplementationBodyCodegen parentBodyCodegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen();
335 parentBodyCodegen.addCompanionObjectPropertyToCopy(propertyDescriptor, defaultValue);
336 }
337
338 String name = backingFieldContext.getFieldName(propertyDescriptor, isDelegate);
339
340 v.getSerializationBindings().put(FIELD_FOR_PROPERTY, propertyDescriptor, Pair.create(type, name));
341
342 FieldVisitor fv = builder.newField(OtherOrigin(element, propertyDescriptor), modifiers, name, type.getDescriptor(),
343 typeMapper.mapFieldSignature(jetType), defaultValue);
344
345 Annotated fieldAnnotated = new AnnotatedWithFakeAnnotations(propertyDescriptor, annotations);
346 AnnotationCodegen.forField(fv, typeMapper).genAnnotations(fieldAnnotated, type, AnnotationUseSiteTarget.FIELD);
347 }
348
349 private void generatePropertyDelegateAccess(JetProperty p, PropertyDescriptor propertyDescriptor, Annotations annotations) {
350 JetExpression delegateExpression = p.getDelegateExpression();
351 JetType delegateType = delegateExpression != null ? bindingContext.getType(p.getDelegateExpression()) : null;
352 if (delegateType == null) {
353 // If delegate expression is unresolved reference
354 delegateType = ErrorUtils.createErrorType("Delegate type");
355 }
356
357 generateBackingField(p, propertyDescriptor, true, delegateType, null, annotations);
358 }
359
360 private void generateBackingFieldAccess(JetNamedDeclaration p, PropertyDescriptor propertyDescriptor, Annotations annotations) {
361 Object value = null;
362
363 if (shouldWriteFieldInitializer(propertyDescriptor)) {
364 ConstantValue<?> initializer = propertyDescriptor.getCompileTimeInitializer();
365 if (initializer != null) {
366 value = initializer.getValue();
367 }
368 }
369
370 generateBackingField(p, propertyDescriptor, false, propertyDescriptor.getType(), value, annotations);
371 }
372
373 private boolean shouldWriteFieldInitializer(@NotNull PropertyDescriptor descriptor) {
374 //final field of primitive or String type
375 if (!descriptor.isVar()) {
376 Type type = typeMapper.mapType(descriptor);
377 return AsmUtil.isPrimitive(type) || "java.lang.String".equals(type.getClassName());
378 }
379 return false;
380 }
381
382 private void generateGetter(@Nullable JetNamedDeclaration p, @NotNull PropertyDescriptor descriptor, @Nullable JetPropertyAccessor getter) {
383 generateAccessor(p, getter, descriptor.getGetter() != null
384 ? descriptor.getGetter()
385 : DescriptorFactory.createDefaultGetter(descriptor, Annotations.EMPTY));
386 }
387
388 private void generateSetter(@Nullable JetNamedDeclaration p, @NotNull PropertyDescriptor descriptor, @Nullable JetPropertyAccessor setter) {
389 if (!descriptor.isVar()) return;
390
391 generateAccessor(p, setter, descriptor.getSetter() != null
392 ? descriptor.getSetter()
393 : DescriptorFactory.createDefaultSetter(descriptor, Annotations.EMPTY));
394 }
395
396 private void generateAccessor(
397 @Nullable JetNamedDeclaration p,
398 @Nullable JetPropertyAccessor accessor,
399 @NotNull PropertyAccessorDescriptor accessorDescriptor
400 ) {
401 FunctionGenerationStrategy strategy;
402 if (accessor == null || !accessor.hasBody()) {
403 if (p instanceof JetProperty && ((JetProperty) p).hasDelegate()) {
404 strategy = new DelegatedPropertyAccessorStrategy(state, accessorDescriptor, indexOfDelegatedProperty((JetProperty) p));
405 }
406 else {
407 strategy = new DefaultPropertyAccessorStrategy(state, accessorDescriptor);
408 }
409 }
410 else {
411 strategy = new FunctionGenerationStrategy.FunctionDefault(state, accessorDescriptor, accessor);
412 }
413
414 functionCodegen.generateMethod(OtherOrigin(accessor != null ? accessor : p, accessorDescriptor), accessorDescriptor, strategy);
415 }
416
417 public static int indexOfDelegatedProperty(@NotNull JetProperty property) {
418 PsiElement parent = property.getParent();
419 JetDeclarationContainer container;
420 if (parent instanceof JetClassBody) {
421 container = ((JetClassOrObject) parent.getParent());
422 }
423 else if (parent instanceof JetFile) {
424 container = (JetFile) parent;
425 }
426 else {
427 throw new UnsupportedOperationException("Unknown delegated property container: " + parent);
428 }
429
430 int index = 0;
431 for (JetDeclaration declaration : container.getDeclarations()) {
432 if (declaration instanceof JetProperty && ((JetProperty) declaration).hasDelegate()) {
433 if (declaration == property) {
434 return index;
435 }
436 index++;
437 }
438 }
439
440 throw new IllegalStateException("Delegated property not found in its parent: " + PsiUtilPackage.getElementTextWithContext(property));
441 }
442
443
444 private static class DefaultPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> {
445 public DefaultPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) {
446 super(state, descriptor);
447 }
448
449 @Override
450 public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
451 InstructionAdapter v = codegen.v;
452 PropertyDescriptor propertyDescriptor = callableDescriptor.getCorrespondingProperty();
453 StackValue property = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0);
454
455 PsiElement jetProperty = DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor);
456 if (jetProperty instanceof JetProperty || jetProperty instanceof JetParameter) {
457 codegen.markLineNumber((JetElement) jetProperty, false);
458 }
459
460 if (callableDescriptor instanceof PropertyGetterDescriptor) {
461 Type type = signature.getReturnType();
462 property.put(type, v);
463 v.areturn(type);
464 }
465 else if (callableDescriptor instanceof PropertySetterDescriptor) {
466 List<ValueParameterDescriptor> valueParameters = callableDescriptor.getValueParameters();
467 assert valueParameters.size() == 1 : "Property setter should have only one value parameter but has " + callableDescriptor;
468 int parameterIndex = codegen.lookupLocalIndex(valueParameters.get(0));
469 assert parameterIndex >= 0 : "Local index for setter parameter should be positive or zero: " + callableDescriptor;
470 Type type = codegen.typeMapper.mapType(propertyDescriptor);
471 property.store(StackValue.local(parameterIndex, type), codegen.v);
472 v.visitInsn(RETURN);
473 }
474 else {
475 throw new IllegalStateException("Unknown property accessor: " + callableDescriptor);
476 }
477 }
478 }
479
480 public static StackValue invokeDelegatedPropertyConventionMethod(
481 @NotNull PropertyDescriptor propertyDescriptor,
482 @NotNull ExpressionCodegen codegen,
483 @NotNull JetTypeMapper typeMapper,
484 @NotNull ResolvedCall<FunctionDescriptor> resolvedCall,
485 final int indexInPropertyMetadataArray,
486 int propertyMetadataArgumentIndex
487 ) {
488 CodegenContext<? extends ClassOrPackageFragmentDescriptor> ownerContext = codegen.getContext().getClassOrPackageParentContext();
489 final Type owner;
490 if (ownerContext instanceof ClassContext) {
491 owner = typeMapper.mapClass(((ClassContext) ownerContext).getContextDescriptor());
492 }
493 else if (ownerContext instanceof PackageContext) {
494 owner = ((PackageContext) ownerContext).getPackagePartType();
495 }
496 else if (ownerContext instanceof MultifileClassContextBase) {
497 owner = ((MultifileClassContextBase) ownerContext).getFilePartType();
498 }
499 else {
500 throw new UnsupportedOperationException("Unknown context: " + ownerContext);
501 }
502
503 codegen.tempVariables.put(
504 resolvedCall.getCall().getValueArguments().get(propertyMetadataArgumentIndex).asElement(),
505 new StackValue(PROPERTY_METADATA_TYPE) {
506 @Override
507 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
508 Field array = StackValue
509 .field(Type.getType("[" + PROPERTY_METADATA_TYPE), owner, JvmAbi.PROPERTY_METADATA_ARRAY_NAME, true,
510 StackValue.none());
511 StackValue.arrayElement(PROPERTY_METADATA_TYPE, array, StackValue.constant(indexInPropertyMetadataArray, Type.INT_TYPE)).put(type, v);
512 }
513 }
514 );
515
516 StackValue delegatedProperty = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0);
517 return codegen.invokeFunction(resolvedCall, delegatedProperty);
518 }
519
520 private static class DelegatedPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> {
521 private final int index;
522
523 public DelegatedPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor, int index) {
524 super(state, descriptor);
525 this.index = index;
526 }
527
528 @Override
529 public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
530 InstructionAdapter v = codegen.v;
531
532 BindingContext bindingContext = state.getBindingContext();
533 ResolvedCall<FunctionDescriptor> resolvedCall =
534 bindingContext.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, callableDescriptor);
535 assert resolvedCall != null : "Resolve call should be recorded for delegate call " + signature.toString();
536
537 StackValue lastValue = invokeDelegatedPropertyConventionMethod(callableDescriptor.getCorrespondingProperty(),
538 codegen, state.getTypeMapper(), resolvedCall, index, 1);
539 Type asmType = signature.getReturnType();
540 lastValue.put(asmType, v);
541 v.areturn(asmType);
542 }
543 }
544
545 public void genDelegate(@NotNull PropertyDescriptor delegate, @NotNull PropertyDescriptor delegateTo, @NotNull StackValue field) {
546 ClassDescriptor toClass = (ClassDescriptor) delegateTo.getContainingDeclaration();
547
548 PropertyGetterDescriptor getter = delegate.getGetter();
549 if (getter != null) {
550 //noinspection ConstantConditions
551 functionCodegen.genDelegate(getter, delegateTo.getGetter().getOriginal(), toClass, field);
552 }
553
554 PropertySetterDescriptor setter = delegate.getSetter();
555 if (setter != null) {
556 //noinspection ConstantConditions
557 functionCodegen.genDelegate(setter, delegateTo.getSetter().getOriginal(), toClass, field);
558 }
559 }
560 }