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