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 }