001/* 002 * Copyright 2010-2013 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 017package org.jetbrains.jet.codegen; 018 019import com.intellij.openapi.util.text.StringUtil; 020import org.jetbrains.annotations.NotNull; 021import org.jetbrains.annotations.Nullable; 022import org.jetbrains.asm4.FieldVisitor; 023import org.jetbrains.asm4.MethodVisitor; 024import org.jetbrains.asm4.Type; 025import org.jetbrains.asm4.commons.InstructionAdapter; 026import org.jetbrains.jet.codegen.context.CodegenContext; 027import org.jetbrains.jet.codegen.context.FieldOwnerContext; 028import org.jetbrains.jet.codegen.signature.JvmMethodSignature; 029import org.jetbrains.jet.codegen.signature.JvmPropertyAccessorSignature; 030import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter; 031import org.jetbrains.jet.codegen.state.GenerationState; 032import org.jetbrains.jet.codegen.state.GenerationStateAware; 033import org.jetbrains.jet.codegen.state.JetTypeMapper; 034import org.jetbrains.jet.lang.descriptors.*; 035import org.jetbrains.jet.lang.psi.*; 036import org.jetbrains.jet.lang.resolve.BindingContext; 037import org.jetbrains.jet.lang.resolve.DescriptorResolver; 038import org.jetbrains.jet.lang.resolve.DescriptorUtils; 039import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; 040import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; 041import org.jetbrains.jet.lang.resolve.java.JvmAbi; 042import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames; 043import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils; 044import org.jetbrains.jet.lang.resolve.name.Name; 045import org.jetbrains.jet.lang.types.ErrorUtils; 046import org.jetbrains.jet.lang.types.JetType; 047import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 048 049import static org.jetbrains.asm4.Opcodes.*; 050import static org.jetbrains.jet.codegen.AsmUtil.getDeprecatedAccessFlag; 051import static org.jetbrains.jet.codegen.AsmUtil.getVisibilityForSpecialPropertyBackingField; 052import static org.jetbrains.jet.codegen.CodegenUtil.*; 053import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE; 054 055public class PropertyCodegen extends GenerationStateAware { 056 @NotNull 057 private final FunctionCodegen functionCodegen; 058 059 @NotNull 060 private final ClassBuilder v; 061 062 @NotNull 063 private final FieldOwnerContext context; 064 065 @Nullable 066 private MemberCodegen classBodyCodegen; 067 068 @NotNull 069 private final OwnerKind kind; 070 071 public PropertyCodegen( 072 @NotNull FieldOwnerContext context, 073 @NotNull ClassBuilder v, 074 @NotNull FunctionCodegen functionCodegen, 075 @Nullable MemberCodegen classBodyCodegen 076 ) { 077 super(functionCodegen.getState()); 078 this.v = v; 079 this.functionCodegen = functionCodegen; 080 this.context = context; 081 this.classBodyCodegen = classBodyCodegen; 082 this.kind = context.getContextKind(); 083 } 084 085 public void gen(JetProperty p) { 086 PropertyDescriptor propertyDescriptor = DescriptorUtils.getPropertyDescriptor(p, bindingContext); 087 assert kind instanceof OwnerKind.StaticDelegateKind || kind == OwnerKind.NAMESPACE || kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.TRAIT_IMPL 088 : "Generating property with a wrong kind (" + kind + "): " + propertyDescriptor; 089 090 if (kind != OwnerKind.TRAIT_IMPL && !(kind instanceof OwnerKind.StaticDelegateKind)) { 091 generateBackingField(p, propertyDescriptor); 092 } 093 generateGetter(p, propertyDescriptor, p.getGetter()); 094 generateSetter(p, propertyDescriptor, p.getSetter()); 095 096 context.recordSyntheticAccessorIfNeeded(propertyDescriptor, typeMapper); 097 } 098 099 public void generatePrimaryConstructorProperty(JetParameter p, PropertyDescriptor descriptor) { 100 generateBackingField(p, descriptor); 101 generateGetter(p, descriptor, null); 102 if (descriptor.isVar()) { 103 generateSetter(p, descriptor, null); 104 } 105 } 106 107 private void generateBackingField(JetNamedDeclaration p, PropertyDescriptor propertyDescriptor) { 108 //noinspection ConstantConditions 109 boolean hasBackingField = bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor); 110 boolean isDelegated = p instanceof JetProperty && ((JetProperty) p).getDelegateExpression() != null; 111 if (hasBackingField || isDelegated) { 112 DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); 113 if (isInterface(containingDeclaration)) { 114 return; 115 } 116 117 FieldVisitor fieldVisitor = hasBackingField 118 ? generateBackingFieldAccess(p, propertyDescriptor) 119 : generatePropertyDelegateAccess((JetProperty) p, propertyDescriptor); 120 121 AnnotationCodegen.forField(fieldVisitor, typeMapper).genAnnotations(propertyDescriptor); 122 } 123 124 } 125 126 private FieldVisitor generateBackingField(JetNamedDeclaration element, PropertyDescriptor propertyDescriptor, boolean isDelegate, JetType jetType, Object defaultValue) { 127 int modifiers = getDeprecatedAccessFlag(propertyDescriptor); 128 129 if (KotlinBuiltIns.getInstance().isVolatile(propertyDescriptor)) { 130 modifiers |= ACC_VOLATILE; 131 } 132 133 if (kind == OwnerKind.NAMESPACE) { 134 modifiers |= ACC_STATIC; 135 } 136 137 if (!propertyDescriptor.isVar() || isDelegate) { 138 modifiers |= ACC_FINAL; 139 } 140 141 Type type = typeMapper.mapType(jetType); 142 143 ClassBuilder builder = v; 144 145 FieldOwnerContext backingFieldContext = context; 146 if (AsmUtil.isPropertyWithBackingFieldInOuterClass(propertyDescriptor)) { 147 modifiers |= ACC_STATIC | getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegate); 148 ImplementationBodyCodegen codegen = getParentBodyCodegen(classBodyCodegen); 149 builder = codegen.v; 150 backingFieldContext = codegen.context; 151 } else { 152 if (kind != OwnerKind.NAMESPACE || isDelegate) { 153 modifiers |= ACC_PRIVATE; 154 } 155 } 156 157 if (AsmUtil.isPropertyWithBackingFieldCopyInOuterClass(propertyDescriptor)) { 158 ImplementationBodyCodegen parentBodyCodegen = getParentBodyCodegen(classBodyCodegen); 159 parentBodyCodegen.addClassObjectPropertyToCopy(propertyDescriptor, defaultValue); 160 } 161 162 String name = backingFieldContext.getFieldName(propertyDescriptor, isDelegate); 163 164 return builder.newField(element, modifiers, name, type.getDescriptor(), 165 typeMapper.mapFieldSignature(jetType), defaultValue); 166 } 167 168 private FieldVisitor generatePropertyDelegateAccess(JetProperty p, PropertyDescriptor propertyDescriptor) { 169 JetType delegateType = bindingContext.get(BindingContext.EXPRESSION_TYPE, p.getDelegateExpression()); 170 if (delegateType == null) { 171 // If delegate expression is unresolved reference 172 delegateType = ErrorUtils.createErrorType("Delegate type"); 173 } 174 175 return generateBackingField(p, propertyDescriptor, true, delegateType, null); 176 } 177 178 private FieldVisitor generateBackingFieldAccess(JetNamedDeclaration p, PropertyDescriptor propertyDescriptor) { 179 Object value = null; 180 181 if (ImplementationBodyCodegen.shouldWriteFieldInitializer(propertyDescriptor, typeMapper)) { 182 JetExpression initializer = p instanceof JetProperty ? ((JetProperty) p).getInitializer() : null; 183 if (initializer != null) { 184 CompileTimeConstant<?> compileTimeValue = bindingContext.get(BindingContext.COMPILE_TIME_VALUE, initializer); 185 value = compileTimeValue != null ? compileTimeValue.getValue() : null; 186 } 187 } 188 189 return generateBackingField(p, propertyDescriptor, false, propertyDescriptor.getType(), value); 190 } 191 192 private void generateGetter(JetNamedDeclaration p, PropertyDescriptor propertyDescriptor, JetPropertyAccessor getter) { 193 boolean defaultGetter = getter == null || getter.getBodyExpression() == null; 194 195 //TODO: Now it's not enough information to properly resolve property from bytecode without generated getter and setter 196 //if (!defaultGetter || isExternallyAccessible(propertyDescriptor)) { 197 JvmPropertyAccessorSignature signature = typeMapper.mapGetterSignature(propertyDescriptor, kind); 198 PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter(); 199 getterDescriptor = getterDescriptor != null ? getterDescriptor : DescriptorResolver.createDefaultGetter(propertyDescriptor); 200 201 if (kind != OwnerKind.TRAIT_IMPL || !defaultGetter) { 202 FunctionGenerationStrategy strategy; 203 if (defaultGetter) { 204 if (p instanceof JetProperty && ((JetProperty) p).getDelegateExpression() != null) { 205 strategy = new DefaultPropertyWithDelegateAccessorStrategy(state, getterDescriptor); 206 } 207 else { 208 strategy = new DefaultPropertyAccessorStrategy(state, getterDescriptor); 209 } 210 } 211 else { 212 strategy = new FunctionGenerationStrategy.FunctionDefault(state, getterDescriptor, getter); 213 } 214 functionCodegen.generateMethod(getter != null ? getter : p, 215 signature, 216 true, 217 getterDescriptor, 218 strategy); 219 } 220 //} 221 } 222 223 private void generateSetter(JetNamedDeclaration p, PropertyDescriptor propertyDescriptor, JetPropertyAccessor setter) { 224 boolean defaultSetter = setter == null || setter.getBodyExpression() == null; 225 226 //TODO: Now it's not enough information to properly resolve property from bytecode without generated getter and setter 227 if (/*!defaultSetter || isExternallyAccessible(propertyDescriptor) &&*/ propertyDescriptor.isVar()) { 228 JvmPropertyAccessorSignature signature = typeMapper.mapSetterSignature(propertyDescriptor, kind); 229 PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter(); 230 setterDescriptor = setterDescriptor != null ? setterDescriptor : DescriptorResolver.createDefaultSetter(propertyDescriptor); 231 232 if (kind != OwnerKind.TRAIT_IMPL || !defaultSetter) { 233 FunctionGenerationStrategy strategy; 234 if (defaultSetter) { 235 if (p instanceof JetProperty && ((JetProperty) p).getDelegateExpression() != null) { 236 strategy = new DefaultPropertyWithDelegateAccessorStrategy(state, setterDescriptor); 237 } 238 else { 239 strategy = new DefaultPropertyAccessorStrategy(state, setterDescriptor); 240 } 241 } 242 else { 243 strategy = new FunctionGenerationStrategy.FunctionDefault(state, setterDescriptor, setter); 244 } 245 functionCodegen.generateMethod(setter != null ? setter : p, 246 signature, 247 true, 248 setterDescriptor, 249 strategy); 250 } 251 } 252 } 253 254 255 private static class DefaultPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> { 256 257 public DefaultPropertyAccessorStrategy( 258 @NotNull GenerationState state, 259 @NotNull PropertyAccessorDescriptor callableDescriptor 260 ) { 261 super(state, callableDescriptor); 262 } 263 264 @Override 265 public void doGenerateBody( 266 ExpressionCodegen codegen, JvmMethodSignature signature 267 ) { 268 generateDefaultAccessor(callableDescriptor, codegen.v, codegen); 269 } 270 } 271 272 private static void generateDefaultAccessor( 273 @NotNull PropertyAccessorDescriptor accessorDescriptor, 274 @NotNull InstructionAdapter iv, 275 @NotNull ExpressionCodegen codegen 276 ) { 277 JetTypeMapper typeMapper = codegen.typeMapper; 278 CodegenContext context = codegen.context; 279 OwnerKind kind = context.getContextKind(); 280 281 PropertyDescriptor propertyDescriptor = accessorDescriptor.getCorrespondingProperty(); 282 Type type = typeMapper.mapType(propertyDescriptor); 283 284 int paramCode = 0; 285 if (kind != OwnerKind.NAMESPACE) { 286 iv.load(0, OBJECT_TYPE); 287 paramCode = 1; 288 } 289 290 StackValue property = codegen.intermediateValueForProperty(accessorDescriptor.getCorrespondingProperty(), true, null); 291 292 if (accessorDescriptor instanceof PropertyGetterDescriptor) { 293 property.put(type, iv); 294 iv.areturn(type); 295 } 296 else if (accessorDescriptor instanceof PropertySetterDescriptor) { 297 ReceiverParameterDescriptor receiverParameter = propertyDescriptor.getReceiverParameter(); 298 if (receiverParameter != null) { 299 paramCode += typeMapper.mapType(receiverParameter.getType()).getSize(); 300 } 301 iv.load(paramCode, type); 302 303 property.store(type, iv); 304 iv.visitInsn(RETURN); 305 } else { 306 assert false : "Unreachable state"; 307 } 308 } 309 310 private static class DefaultPropertyWithDelegateAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> { 311 public DefaultPropertyWithDelegateAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) { 312 super(state, descriptor); 313 } 314 315 @Override 316 public void doGenerateBody( 317 @NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature 318 ) { 319 JetTypeMapper typeMapper = codegen.typeMapper; 320 OwnerKind kind = codegen.context.getContextKind(); 321 InstructionAdapter iv = codegen.v; 322 BindingContext bindingContext = state.getBindingContext(); 323 324 ResolvedCall<FunctionDescriptor> resolvedCall = 325 bindingContext.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, callableDescriptor); 326 327 Call call = bindingContext.get(BindingContext.DELEGATED_PROPERTY_CALL, callableDescriptor); 328 assert call != null : "Call should be recorded for delegate call " + signature.toString(); 329 330 PropertyDescriptor property = callableDescriptor.getCorrespondingProperty(); 331 Type asmType = typeMapper.mapType(property); 332 333 if (kind != OwnerKind.NAMESPACE) { 334 iv.load(0, OBJECT_TYPE); 335 } 336 337 StackValue delegatedProperty = codegen.intermediateValueForProperty(property, true, null); 338 StackValue lastValue = codegen.invokeFunction(call, delegatedProperty, resolvedCall); 339 340 if (lastValue.type != Type.VOID_TYPE) { 341 lastValue.put(asmType, iv); 342 iv.areturn(asmType); 343 } 344 else { 345 iv.areturn(Type.VOID_TYPE); 346 } 347 } 348 } 349 350 public static void generateJetPropertyAnnotation( 351 MethodVisitor mv, @NotNull JvmPropertyAccessorSignature propertyAccessorSignature, 352 @NotNull PropertyDescriptor propertyDescriptor, @NotNull Visibility visibility 353 ) { 354 JetMethodAnnotationWriter aw = JetMethodAnnotationWriter.visitAnnotation(mv); 355 Modality modality = propertyDescriptor.getModality(); 356 int flags = getFlagsForVisibility(visibility) | JvmStdlibNames.FLAG_PROPERTY_BIT; 357 if (isInterface(propertyDescriptor.getContainingDeclaration()) && modality != Modality.ABSTRACT) { 358 flags |= modality == Modality.FINAL 359 ? JvmStdlibNames.FLAG_FORCE_FINAL_BIT 360 : JvmStdlibNames.FLAG_FORCE_OPEN_BIT; 361 } 362 aw.writeFlags(flags | DescriptorKindUtils.kindToFlags(propertyDescriptor.getKind())); 363 aw.writeTypeParameters(propertyAccessorSignature.getKotlinTypeParameter()); 364 aw.writePropertyType(propertyAccessorSignature.getPropertyTypeKotlinSignature()); 365 aw.visitEnd(); 366 } 367 368 public static String getterName(Name propertyName) { 369 return JvmAbi.GETTER_PREFIX + StringUtil.capitalizeWithJavaBeanConvention(propertyName.asString()); 370 } 371 372 public static String setterName(Name propertyName) { 373 return JvmAbi.SETTER_PREFIX + StringUtil.capitalizeWithJavaBeanConvention(propertyName.asString()); 374 } 375 376 public void genDelegate(PropertyDescriptor delegate, PropertyDescriptor overridden, StackValue field) { 377 ClassDescriptor toClass = (ClassDescriptor) overridden.getContainingDeclaration(); 378 379 functionCodegen.genDelegate(delegate.getGetter(), toClass, field, 380 typeMapper.mapGetterSignature(delegate, OwnerKind.IMPLEMENTATION), 381 typeMapper.mapGetterSignature(overridden.getOriginal(), OwnerKind.IMPLEMENTATION)); 382 383 if (delegate.isVar()) { 384 functionCodegen.genDelegate(delegate.getSetter(), toClass, field, 385 typeMapper.mapSetterSignature(delegate, OwnerKind.IMPLEMENTATION), 386 typeMapper.mapSetterSignature(overridden.getOriginal(), OwnerKind.IMPLEMENTATION)); 387 } 388 } 389}