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