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