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 assert declaration != null : "Declaration is null: " + descriptor + " (context=" + context + ")"; 124 genBackingFieldAndAnnotations(declaration, descriptor, false); 125 126 if (isAccessorNeeded(declaration, descriptor, getter)) { 127 generateGetter(declaration, descriptor, getter); 128 } 129 if (isAccessorNeeded(declaration, descriptor, setter)) { 130 generateSetter(declaration, descriptor, setter); 131 } 132 } 133 134 private void genBackingFieldAndAnnotations(@NotNull KtNamedDeclaration declaration, @NotNull PropertyDescriptor descriptor, boolean isParameter) { 135 boolean hasBackingField = hasBackingField(declaration, descriptor); 136 boolean hasDelegate = declaration instanceof KtProperty && ((KtProperty) declaration).hasDelegate(); 137 138 AnnotationSplitter annotationSplitter = 139 AnnotationSplitter.create(LockBasedStorageManager.NO_LOCKS, 140 descriptor.getAnnotations(), 141 AnnotationSplitter.getTargetSet(isParameter, descriptor.isVar(), hasBackingField, hasDelegate)); 142 143 Annotations propertyAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY); 144 145 // Fields and '$annotations' methods for non-private const properties are generated in the multi-file facade 146 boolean isBackingFieldOwner = descriptor.isConst() && !Visibilities.isPrivate(descriptor.getVisibility()) 147 ? !(context instanceof MultifileClassPartContext) 148 : CodegenContextUtil.isImplClassOwner(context); 149 150 if (isBackingFieldOwner) { 151 Annotations fieldAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.FIELD); 152 Annotations delegateAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD); 153 generateBackingField(declaration, descriptor, fieldAnnotations, delegateAnnotations); 154 generateSyntheticMethodIfNeeded(descriptor, propertyAnnotations); 155 } 156 157 if (!propertyAnnotations.getAllAnnotations().isEmpty() && kind != OwnerKind.DEFAULT_IMPLS && 158 CodegenContextUtil.isImplClassOwner(context)) { 159 v.getSerializationBindings().put(SYNTHETIC_METHOD_FOR_PROPERTY, descriptor, getSyntheticMethodSignature(descriptor)); 160 } 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 // Non-const properties from multifile classes have accessors regardless of visibility 190 if (!descriptor.isConst() && JvmFileClassUtilKt.isInsideJvmMultifileClassFile(declaration)) return true; 191 192 // Private class properties have accessors only in cases when those accessors are non-trivial 193 if (Visibilities.isPrivate(descriptor.getVisibility())) { 194 return !isDefaultAccessor; 195 } 196 197 return true; 198 } 199 200 private static boolean areAccessorsNeededForPrimaryConstructorProperty( 201 @NotNull PropertyDescriptor descriptor 202 ) { 203 if (hasJvmFieldAnnotation(descriptor)) return false; 204 205 return !Visibilities.isPrivate(descriptor.getVisibility()); 206 } 207 208 public void generatePrimaryConstructorProperty(@NotNull KtParameter p, @NotNull PropertyDescriptor descriptor) { 209 genBackingFieldAndAnnotations(p, descriptor, true); 210 211 if (areAccessorsNeededForPrimaryConstructorProperty(descriptor)) { 212 generateGetter(p, descriptor, null); 213 generateSetter(p, descriptor, null); 214 } 215 } 216 217 public void generateConstructorPropertyAsMethodForAnnotationClass(KtParameter p, PropertyDescriptor descriptor) { 218 JvmMethodGenericSignature signature = typeMapper.mapAnnotationParameterSignature(descriptor); 219 String name = p.getName(); 220 if (name == null) return; 221 MethodVisitor mv = v.newMethod( 222 JvmDeclarationOriginKt.OtherOrigin(p, descriptor), ACC_PUBLIC | ACC_ABSTRACT, name, 223 signature.getAsmMethod().getDescriptor(), 224 signature.getGenericsSignature(), 225 null 226 ); 227 228 KtExpression defaultValue = p.getDefaultValue(); 229 if (defaultValue != null) { 230 ConstantValue<?> constant = ExpressionCodegen.getCompileTimeConstant(defaultValue, bindingContext, true); 231 assert state.getClassBuilderMode() != ClassBuilderMode.FULL || constant != null 232 : "Default value for annotation parameter should be compile time value: " + defaultValue.getText(); 233 if (constant != null) { 234 AnnotationCodegen annotationCodegen = AnnotationCodegen.forAnnotationDefaultValue(mv, typeMapper); 235 annotationCodegen.generateAnnotationDefaultValue(constant, descriptor.getType()); 236 } 237 } 238 239 mv.visitEnd(); 240 } 241 242 private boolean hasBackingField(@NotNull KtNamedDeclaration p, @NotNull PropertyDescriptor descriptor) { 243 return !isJvmInterface(descriptor.getContainingDeclaration()) && 244 kind != OwnerKind.DEFAULT_IMPLS && 245 !Boolean.FALSE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor)); 246 } 247 248 private boolean generateBackingField( 249 @NotNull KtNamedDeclaration p, 250 @NotNull PropertyDescriptor descriptor, 251 @NotNull Annotations backingFieldAnnotations, 252 @NotNull Annotations delegateAnnotations 253 ) { 254 if (isJvmInterface(descriptor.getContainingDeclaration()) || kind == OwnerKind.DEFAULT_IMPLS) { 255 return false; 256 } 257 258 if (p instanceof KtProperty && ((KtProperty) p).hasDelegate()) { 259 generatePropertyDelegateAccess((KtProperty) p, descriptor, delegateAnnotations); 260 } 261 else if (Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor))) { 262 generateBackingFieldAccess(p, descriptor, backingFieldAnnotations); 263 } 264 else { 265 return false; 266 } 267 return true; 268 } 269 270 // Annotations on properties are stored in bytecode on an empty synthetic method. This way they're still 271 // accessible via reflection, and 'deprecated' and 'private' flags prevent this method from being called accidentally 272 private void generateSyntheticMethodIfNeeded(@NotNull PropertyDescriptor descriptor, @NotNull Annotations annotations) { 273 if (annotations.getAllAnnotations().isEmpty()) return; 274 275 if (!isInterface(context.getContextDescriptor()) || kind == OwnerKind.DEFAULT_IMPLS) { 276 int flags = ACC_DEPRECATED | ACC_FINAL | ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC; 277 Method syntheticMethod = getSyntheticMethodSignature(descriptor); 278 MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(descriptor), flags, syntheticMethod.getName(), 279 syntheticMethod.getDescriptor(), null, null); 280 AnnotationCodegen.forMethod(mv, typeMapper) 281 .genAnnotations(new AnnotatedSimple(annotations), Type.VOID_TYPE, AnnotationUseSiteTarget.PROPERTY); 282 mv.visitCode(); 283 mv.visitInsn(Opcodes.RETURN); 284 mv.visitEnd(); 285 } 286 } 287 288 @NotNull 289 private Method getSyntheticMethodSignature(@NotNull PropertyDescriptor descriptor) { 290 ReceiverParameterDescriptor receiver = descriptor.getExtensionReceiverParameter(); 291 String name = JvmAbi.getSyntheticMethodNameForAnnotatedProperty(descriptor.getName()); 292 String desc = receiver == null ? "()V" : "(" + typeMapper.mapType(receiver.getType()) + ")V"; 293 return new Method(name, desc); 294 } 295 296 private void generateBackingField( 297 KtNamedDeclaration element, 298 PropertyDescriptor propertyDescriptor, 299 boolean isDelegate, 300 KotlinType kotlinType, 301 Object defaultValue, 302 Annotations annotations 303 ) { 304 int modifiers = getDeprecatedAccessFlag(propertyDescriptor); 305 306 for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.FIELD_FLAGS) { 307 if (flagAnnotation.hasAnnotation(propertyDescriptor.getOriginal())) { 308 modifiers |= flagAnnotation.getJvmFlag(); 309 } 310 } 311 312 if (kind == OwnerKind.PACKAGE) { 313 modifiers |= ACC_STATIC; 314 } 315 316 if (!propertyDescriptor.isLateInit() && (!propertyDescriptor.isVar() || isDelegate)) { 317 modifiers |= ACC_FINAL; 318 } 319 320 if (AnnotationUtilKt.hasJvmSyntheticAnnotation(propertyDescriptor)) { 321 modifiers |= ACC_SYNTHETIC; 322 } 323 324 Type type = typeMapper.mapType(kotlinType); 325 326 ClassBuilder builder = v; 327 328 FieldOwnerContext backingFieldContext = context; 329 if (AsmUtil.isInstancePropertyWithStaticBackingField(propertyDescriptor) ) { 330 modifiers |= ACC_STATIC; 331 332 if (JvmAbi.isPropertyWithBackingFieldInOuterClass(propertyDescriptor)) { 333 ImplementationBodyCodegen codegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen(); 334 builder = codegen.v; 335 backingFieldContext = codegen.context; 336 } 337 } 338 modifiers |= getVisibilityForBackingField(propertyDescriptor, isDelegate); 339 340 if (AsmUtil.isPropertyWithBackingFieldCopyInOuterClass(propertyDescriptor)) { 341 ImplementationBodyCodegen parentBodyCodegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen(); 342 parentBodyCodegen.addCompanionObjectPropertyToCopy(propertyDescriptor, defaultValue); 343 } 344 345 String name = backingFieldContext.getFieldName(propertyDescriptor, isDelegate); 346 347 v.getSerializationBindings().put(FIELD_FOR_PROPERTY, propertyDescriptor, Pair.create(type, name)); 348 349 FieldVisitor fv = builder.newField( 350 JvmDeclarationOriginKt.OtherOrigin(element, propertyDescriptor), modifiers, name, type.getDescriptor(), 351 isDelegate ? null : typeMapper.mapFieldSignature(kotlinType, propertyDescriptor), defaultValue 352 ); 353 354 Annotated fieldAnnotated = new AnnotatedWithFakeAnnotations(propertyDescriptor, annotations); 355 AnnotationCodegen.forField(fv, typeMapper).genAnnotations( 356 fieldAnnotated, type, isDelegate ? AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD : AnnotationUseSiteTarget.FIELD); 357 } 358 359 private void generatePropertyDelegateAccess( 360 @NotNull KtProperty p, 361 @NotNull PropertyDescriptor propertyDescriptor, 362 @NotNull Annotations annotations 363 ) { 364 KtExpression delegateExpression = p.getDelegateExpression(); 365 KotlinType delegateType = delegateExpression != null ? bindingContext.getType(p.getDelegateExpression()) : null; 366 if (delegateType == null) { 367 // If delegate expression is unresolved reference 368 delegateType = ErrorUtils.createErrorType("Delegate type"); 369 } 370 371 generateBackingField(p, propertyDescriptor, true, delegateType, null, annotations); 372 } 373 374 private void generateBackingFieldAccess( 375 @NotNull KtNamedDeclaration p, 376 @NotNull PropertyDescriptor propertyDescriptor, 377 @NotNull Annotations annotations 378 ) { 379 Object value = null; 380 381 if (shouldWriteFieldInitializer(propertyDescriptor)) { 382 ConstantValue<?> initializer = propertyDescriptor.getCompileTimeInitializer(); 383 if (initializer != null) { 384 value = initializer.getValue(); 385 } 386 } 387 388 generateBackingField(p, propertyDescriptor, false, propertyDescriptor.getType(), value, annotations); 389 } 390 391 private boolean shouldWriteFieldInitializer(@NotNull PropertyDescriptor descriptor) { 392 //final field of primitive or String type 393 if (!descriptor.isVar()) { 394 Type type = typeMapper.mapType(descriptor); 395 return AsmUtil.isPrimitive(type) || "java.lang.String".equals(type.getClassName()); 396 } 397 return false; 398 } 399 400 private void generateGetter(@Nullable KtNamedDeclaration p, @NotNull PropertyDescriptor descriptor, @Nullable KtPropertyAccessor getter) { 401 generateAccessor(p, getter, descriptor.getGetter() != null 402 ? descriptor.getGetter() 403 : DescriptorFactory.createDefaultGetter(descriptor, Annotations.Companion.getEMPTY())); 404 } 405 406 private void generateSetter(@Nullable KtNamedDeclaration p, @NotNull PropertyDescriptor descriptor, @Nullable KtPropertyAccessor setter) { 407 if (!descriptor.isVar()) return; 408 409 generateAccessor(p, setter, descriptor.getSetter() != null 410 ? descriptor.getSetter() 411 : DescriptorFactory.createDefaultSetter(descriptor, Annotations.Companion.getEMPTY())); 412 } 413 414 private void generateAccessor( 415 @Nullable KtNamedDeclaration p, 416 @Nullable KtPropertyAccessor accessor, 417 @NotNull PropertyAccessorDescriptor accessorDescriptor 418 ) { 419 if (context instanceof MultifileClassFacadeContext && Visibilities.isPrivate(accessorDescriptor.getVisibility())) { 420 return; 421 } 422 423 FunctionGenerationStrategy strategy; 424 if (accessor == null || !accessor.hasBody()) { 425 if (p instanceof KtProperty && ((KtProperty) p).hasDelegate()) { 426 strategy = new DelegatedPropertyAccessorStrategy(state, accessorDescriptor, indexOfDelegatedProperty((KtProperty) p)); 427 } 428 else { 429 strategy = new DefaultPropertyAccessorStrategy(state, accessorDescriptor); 430 } 431 } 432 else { 433 strategy = new FunctionGenerationStrategy.FunctionDefault(state, accessorDescriptor, accessor); 434 } 435 436 functionCodegen.generateMethod(JvmDeclarationOriginKt.OtherOrigin(accessor != null ? accessor : p, accessorDescriptor), accessorDescriptor, strategy); 437 } 438 439 public static int indexOfDelegatedProperty(@NotNull KtProperty property) { 440 PsiElement parent = property.getParent(); 441 KtDeclarationContainer container; 442 if (parent instanceof KtClassBody) { 443 container = ((KtClassOrObject) parent.getParent()); 444 } 445 else if (parent instanceof KtFile) { 446 container = (KtFile) parent; 447 } 448 else { 449 throw new UnsupportedOperationException("Unknown delegated property container: " + parent); 450 } 451 452 int index = 0; 453 for (KtDeclaration declaration : container.getDeclarations()) { 454 if (declaration instanceof KtProperty && ((KtProperty) declaration).hasDelegate()) { 455 if (declaration == property) { 456 return index; 457 } 458 index++; 459 } 460 } 461 462 throw new IllegalStateException("Delegated property not found in its parent: " + PsiUtilsKt.getElementTextWithContext(property)); 463 } 464 465 466 private static class DefaultPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> { 467 public DefaultPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) { 468 super(state, descriptor); 469 } 470 471 @Override 472 public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { 473 InstructionAdapter v = codegen.v; 474 PropertyDescriptor propertyDescriptor = callableDescriptor.getCorrespondingProperty(); 475 StackValue property = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0); 476 477 PsiElement jetProperty = DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor); 478 if (jetProperty instanceof KtProperty || jetProperty instanceof KtParameter) { 479 codegen.markLineNumber((KtElement) jetProperty, false); 480 } 481 482 if (callableDescriptor instanceof PropertyGetterDescriptor) { 483 Type type = signature.getReturnType(); 484 property.put(type, v); 485 v.areturn(type); 486 } 487 else if (callableDescriptor instanceof PropertySetterDescriptor) { 488 List<ValueParameterDescriptor> valueParameters = callableDescriptor.getValueParameters(); 489 assert valueParameters.size() == 1 : "Property setter should have only one value parameter but has " + callableDescriptor; 490 int parameterIndex = codegen.lookupLocalIndex(valueParameters.get(0)); 491 assert parameterIndex >= 0 : "Local index for setter parameter should be positive or zero: " + callableDescriptor; 492 Type type = codegen.typeMapper.mapType(propertyDescriptor); 493 property.store(StackValue.local(parameterIndex, type), codegen.v); 494 v.visitInsn(RETURN); 495 } 496 else { 497 throw new IllegalStateException("Unknown property accessor: " + callableDescriptor); 498 } 499 } 500 } 501 502 public static StackValue invokeDelegatedPropertyConventionMethod( 503 @NotNull PropertyDescriptor propertyDescriptor, 504 @NotNull ExpressionCodegen codegen, 505 @NotNull KotlinTypeMapper typeMapper, 506 @NotNull ResolvedCall<FunctionDescriptor> resolvedCall, 507 final int indexInPropertyMetadataArray, 508 int propertyMetadataArgumentIndex 509 ) { 510 CodegenContext<? extends ClassOrPackageFragmentDescriptor> ownerContext = codegen.getContext().getClassOrPackageParentContext(); 511 final Type owner; 512 if (ownerContext instanceof ClassContext) { 513 owner = typeMapper.mapClass(((ClassContext) ownerContext).getContextDescriptor()); 514 } 515 else if (ownerContext instanceof PackageContext) { 516 owner = ((PackageContext) ownerContext).getPackagePartType(); 517 } 518 else if (ownerContext instanceof MultifileClassContextBase) { 519 owner = ((MultifileClassContextBase) ownerContext).getFilePartType(); 520 } 521 else { 522 throw new UnsupportedOperationException("Unknown context: " + ownerContext); 523 } 524 525 codegen.tempVariables.put( 526 resolvedCall.getCall().getValueArguments().get(propertyMetadataArgumentIndex).asElement(), 527 new StackValue(K_PROPERTY_TYPE) { 528 @Override 529 public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) { 530 Field array = StackValue.field( 531 Type.getType("[" + K_PROPERTY_TYPE), owner, JvmAbi.DELEGATED_PROPERTIES_ARRAY_NAME, true, StackValue.none() 532 ); 533 StackValue.arrayElement( 534 K_PROPERTY_TYPE, array, StackValue.constant(indexInPropertyMetadataArray, Type.INT_TYPE) 535 ).put(type, v); 536 } 537 } 538 ); 539 540 StackValue delegatedProperty = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0); 541 return codegen.invokeFunction(resolvedCall, delegatedProperty); 542 } 543 544 private static class DelegatedPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> { 545 private final int index; 546 547 public DelegatedPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor, int index) { 548 super(state, descriptor); 549 this.index = index; 550 } 551 552 @Override 553 public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { 554 InstructionAdapter v = codegen.v; 555 556 BindingContext bindingContext = state.getBindingContext(); 557 ResolvedCall<FunctionDescriptor> resolvedCall = 558 bindingContext.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, callableDescriptor); 559 assert resolvedCall != null : "Resolve call should be recorded for delegate call " + signature.toString(); 560 561 StackValue lastValue = invokeDelegatedPropertyConventionMethod(callableDescriptor.getCorrespondingProperty(), 562 codegen, state.getTypeMapper(), resolvedCall, index, 1); 563 Type asmType = signature.getReturnType(); 564 lastValue.put(asmType, v); 565 v.areturn(asmType); 566 } 567 } 568 569 public void genDelegate(@NotNull PropertyDescriptor delegate, @NotNull PropertyDescriptor delegateTo, @NotNull StackValue field) { 570 ClassDescriptor toClass = (ClassDescriptor) delegateTo.getContainingDeclaration(); 571 572 PropertyGetterDescriptor getter = delegate.getGetter(); 573 if (getter != null) { 574 //noinspection ConstantConditions 575 functionCodegen.genDelegate(getter, delegateTo.getGetter().getOriginal(), toClass, field); 576 } 577 578 PropertySetterDescriptor setter = delegate.getSetter(); 579 if (setter != null) { 580 //noinspection ConstantConditions 581 functionCodegen.genDelegate(setter, delegateTo.getSetter().getOriginal(), toClass, field); 582 } 583 } 584 }