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