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