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