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