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