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 }