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