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