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.google.common.collect.Lists;
020 import com.google.common.collect.Sets;
021 import com.intellij.openapi.progress.ProcessCanceledException;
022 import com.intellij.openapi.util.Pair;
023 import com.intellij.psi.PsiElement;
024 import com.intellij.util.ArrayUtil;
025 import org.jetbrains.annotations.NotNull;
026 import org.jetbrains.annotations.Nullable;
027 import org.jetbrains.asm4.AnnotationVisitor;
028 import org.jetbrains.asm4.Label;
029 import org.jetbrains.asm4.MethodVisitor;
030 import org.jetbrains.asm4.Type;
031 import org.jetbrains.asm4.commons.InstructionAdapter;
032 import org.jetbrains.asm4.commons.Method;
033 import org.jetbrains.jet.codegen.binding.CalculatedClosure;
034 import org.jetbrains.jet.codegen.binding.CodegenBinding;
035 import org.jetbrains.jet.codegen.binding.MutableClosure;
036 import org.jetbrains.jet.codegen.context.ClassContext;
037 import org.jetbrains.jet.codegen.context.ConstructorContext;
038 import org.jetbrains.jet.codegen.context.MethodContext;
039 import org.jetbrains.jet.codegen.signature.*;
040 import org.jetbrains.jet.codegen.state.GenerationState;
041 import org.jetbrains.jet.codegen.state.JetTypeMapper;
042 import org.jetbrains.jet.codegen.state.JetTypeMapperMode;
043 import org.jetbrains.jet.descriptors.serialization.ClassData;
044 import org.jetbrains.jet.descriptors.serialization.DescriptorSerializer;
045 import org.jetbrains.jet.descriptors.serialization.JavaProtoBufUtil;
046 import org.jetbrains.jet.descriptors.serialization.ProtoBuf;
047 import org.jetbrains.jet.lang.descriptors.*;
048 import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
049 import org.jetbrains.jet.lang.psi.*;
050 import org.jetbrains.jet.lang.resolve.BindingContext;
051 import org.jetbrains.jet.lang.resolve.BindingContextUtils;
052 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
053 import org.jetbrains.jet.lang.resolve.OverridingUtil;
054 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
055 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
056 import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
057 import org.jetbrains.jet.lang.resolve.java.JvmAbi;
058 import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames;
059 import org.jetbrains.jet.lang.resolve.java.JvmClassName;
060 import org.jetbrains.jet.lang.resolve.name.Name;
061 import org.jetbrains.jet.lang.types.JetType;
062 import org.jetbrains.jet.lang.types.TypeUtils;
063 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
064 import org.jetbrains.jet.lexer.JetTokens;
065
066 import java.util.*;
067
068 import static org.jetbrains.asm4.Opcodes.*;
069 import static org.jetbrains.jet.codegen.AsmUtil.*;
070 import static org.jetbrains.jet.codegen.CodegenUtil.*;
071 import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
072 import static org.jetbrains.jet.descriptors.serialization.NameSerializationUtil.createNameResolver;
073 import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration;
074 import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration;
075 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
076 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE;
077 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
078
079 public class ImplementationBodyCodegen extends ClassBodyCodegen {
080 private static final String VALUES = "$VALUES";
081 private JetDelegationSpecifier superCall;
082 private Type superClassAsmType;
083 @Nullable // null means java/lang/Object
084 private JetType superClassType;
085 private final Type classAsmType;
086
087 private final FunctionCodegen functionCodegen;
088 private final PropertyCodegen propertyCodegen;
089
090 private List<PropertyAndDefaultValue> classObjectPropertiesToCopy;
091
092 public ImplementationBodyCodegen(
093 @NotNull JetClassOrObject aClass,
094 @NotNull ClassContext context,
095 @NotNull ClassBuilder v,
096 @NotNull GenerationState state,
097 @Nullable MemberCodegen parentCodegen
098 ) {
099 super(aClass, context, v, state, parentCodegen);
100 this.classAsmType = typeMapper.mapType(descriptor.getDefaultType(), JetTypeMapperMode.IMPL);
101 this.functionCodegen = new FunctionCodegen(context, v, state);
102 this.propertyCodegen = new PropertyCodegen(context, v, this.functionCodegen, this);
103 }
104
105 @Override
106 protected void generateDeclaration() {
107 getSuperClass();
108
109 JvmClassSignature signature = signature();
110
111 boolean isAbstract = false;
112 boolean isInterface = false;
113 boolean isFinal = false;
114 boolean isStatic;
115 boolean isAnnotation = false;
116 boolean isEnum = false;
117
118 if (myClass instanceof JetClass) {
119 JetClass jetClass = (JetClass) myClass;
120 if (jetClass.hasModifier(JetTokens.ABSTRACT_KEYWORD)) {
121 isAbstract = true;
122 }
123 if (jetClass.isTrait()) {
124 isAbstract = true;
125 isInterface = true;
126 }
127 else if (jetClass.isAnnotation()) {
128 isAbstract = true;
129 isInterface = true;
130 isAnnotation = true;
131 signature.getInterfaces().add("java/lang/annotation/Annotation");
132 }
133 else if (jetClass.isEnum()) {
134 isAbstract = hasAbstractMembers(descriptor);
135 isEnum = true;
136 }
137
138 if (descriptor.getKind() == ClassKind.OBJECT || descriptor.getKind() == ClassKind.CLASS_OBJECT) {
139 isFinal = true;
140 }
141
142 if (!jetClass.hasModifier(JetTokens.OPEN_KEYWORD) && !isAbstract) {
143 isFinal = true;
144 }
145 isStatic = !jetClass.isInner();
146 }
147 else {
148 isStatic = myClass.getParent() instanceof JetClassObject;
149 isFinal = true;
150 }
151
152 int access = 0;
153
154 if (state.getClassBuilderMode() == ClassBuilderMode.SIGNATURES && !DescriptorUtils.isTopLevelDeclaration(descriptor)) {
155 // ClassBuilderMode.SIGNATURES means we are generating light classes & looking at a nested or inner class
156 // Light class generation is implemented so that Cls-classes only read bare code of classes,
157 // without knowing whether these classes are inner or not (see ClassStubBuilder.EMPTY_STRATEGY)
158 // Thus we must write full accessibility flags on inner classes in this mode
159 access |= getVisibilityAccessFlag(descriptor);
160 // Same for STATIC
161 if (isStatic) {
162 access |= ACC_STATIC;
163 }
164 }
165 else {
166 access |= getVisibilityAccessFlagForClass(descriptor);
167 }
168 if (isAbstract) {
169 access |= ACC_ABSTRACT;
170 }
171 if (isInterface) {
172 access |= ACC_INTERFACE; // ACC_SUPER
173 }
174 else {
175 access |= ACC_SUPER;
176 }
177 if (isFinal) {
178 access |= ACC_FINAL;
179 }
180 if (isAnnotation) {
181 access |= ACC_ANNOTATION;
182 }
183 if (KotlinBuiltIns.getInstance().isDeprecated(descriptor)) {
184 access |= ACC_DEPRECATED;
185 }
186 if (isEnum) {
187 for (JetDeclaration declaration : myClass.getDeclarations()) {
188 if (declaration instanceof JetEnumEntry) {
189 if (enumEntryNeedSubclass(state.getBindingContext(), (JetEnumEntry) declaration)) {
190 access &= ~ACC_FINAL;
191 }
192 }
193 }
194 access |= ACC_ENUM;
195 }
196 List<String> interfaces = signature.getInterfaces();
197 v.defineClass(myClass, V1_6,
198 access,
199 signature.getName(),
200 signature.getJavaGenericSignature(),
201 signature.getSuperclassName(),
202 ArrayUtil.toStringArray(interfaces)
203 );
204 v.visitSource(myClass.getContainingFile().getName(), null);
205
206 writeEnclosingMethod();
207
208 writeOuterClasses();
209
210 writeInnerClasses();
211
212 AnnotationCodegen.forClass(v.getVisitor(), typeMapper).genAnnotations(descriptor);
213 }
214
215 @Override
216 protected void generateKotlinAnnotation() {
217 if (state.getClassBuilderMode() != ClassBuilderMode.FULL) {
218 return;
219 }
220
221 if (!isTopLevelOrInnerClass(descriptor)) return;
222
223 DescriptorSerializer serializer = new DescriptorSerializer(new JavaSerializerExtension(v.getMemberMap()));
224
225 ProtoBuf.Class classProto = serializer.classProto(descriptor).build();
226
227 ClassData data = new ClassData(createNameResolver(serializer.getNameTable()), classProto);
228
229 AnnotationVisitor av = v.getVisitor().visitAnnotation(JvmAnnotationNames.KOTLIN_CLASS.getDescriptor(), true);
230 av.visit(JvmAnnotationNames.ABI_VERSION_FIELD_NAME, JvmAbi.VERSION);
231 AnnotationVisitor array = av.visitArray(JvmAnnotationNames.DATA_FIELD_NAME);
232 for (String string : JavaProtoBufUtil.encodeBytes(data.toBytes())) {
233 array.visit(null, string);
234 }
235 array.visitEnd();
236 av.visitEnd();
237 }
238
239 private void writeEnclosingMethod() {
240 //JVMS7: A class must have an EnclosingMethod attribute if and only if it is a local class or an anonymous class.
241 DeclarationDescriptor parentDescriptor = descriptor.getContainingDeclaration();
242
243 boolean isObjectLiteral = DescriptorUtils.isAnonymous(descriptor);
244
245 boolean isLocalOrAnonymousClass = isObjectLiteral ||
246 !(parentDescriptor instanceof NamespaceDescriptor || parentDescriptor instanceof ClassDescriptor);
247 if (isLocalOrAnonymousClass) {
248 String outerClassName = getOuterClassName(descriptor, typeMapper);
249 FunctionDescriptor function = DescriptorUtils.getParentOfType(descriptor, FunctionDescriptor.class);
250
251 if (function != null) {
252 Method method = typeMapper.mapSignature(function).getAsmMethod();
253 v.visitOuterClass(outerClassName, method.getName(), method.getDescriptor());
254 }
255 else {
256 assert isObjectLiteral
257 : "Function descriptor could be null only for object literal in package namespace: " + descriptor.getName();
258 v.visitOuterClass(outerClassName, null, null);
259 }
260 }
261 }
262
263 @NotNull
264 private static String getOuterClassName(
265 @NotNull ClassDescriptor classDescriptor,
266 @NotNull JetTypeMapper typeMapper
267 ) {
268 ClassDescriptor container = DescriptorUtils.getParentOfType(classDescriptor, ClassDescriptor.class);
269 if (container != null) {
270 return typeMapper.mapType(container.getDefaultType(), JetTypeMapperMode.IMPL).getInternalName();
271 }
272 else {
273 JetFile containingFile = BindingContextUtils.getContainingFile(typeMapper.getBindingContext(), classDescriptor);
274 assert containingFile != null : "Containing file should be present for " + classDescriptor;
275 return NamespaceCodegen.getNamespacePartInternalName(containingFile);
276 }
277 }
278
279 private void writeInnerClasses() {
280 Collection<ClassDescriptor> result = bindingContext.get(INNER_CLASSES, descriptor);
281 if (result != null) {
282 for (ClassDescriptor innerClass : result) {
283 writeInnerClass(innerClass);
284 }
285 }
286 }
287
288 private void writeOuterClasses() {
289 // JVMS7 (4.7.6): a nested class or interface member will have InnerClasses information
290 // for each enclosing class and for each immediate member
291 DeclarationDescriptor inner = descriptor;
292 while (true) {
293 if (inner == null || isTopLevelDeclaration(inner)) {
294 break;
295 }
296 if (inner instanceof ClassDescriptor && !isEnumClassObject(inner)) {
297 writeInnerClass((ClassDescriptor) inner);
298 }
299 inner = inner.getContainingDeclaration();
300 }
301 }
302
303 private void writeInnerClass(@NotNull ClassDescriptor innerClass) {
304 // TODO: proper access
305 int innerClassAccess = getVisibilityAccessFlag(innerClass);
306 if (innerClass.getModality() == Modality.FINAL) {
307 innerClassAccess |= ACC_FINAL;
308 }
309 else if (innerClass.getModality() == Modality.ABSTRACT) {
310 innerClassAccess |= ACC_ABSTRACT;
311 }
312
313 if (innerClass.getKind() == ClassKind.TRAIT) {
314 innerClassAccess |= ACC_INTERFACE;
315 }
316 else if (innerClass.getKind() == ClassKind.ENUM_CLASS) {
317 innerClassAccess |= ACC_ENUM;
318 }
319
320 if (!innerClass.isInner()) {
321 innerClassAccess |= ACC_STATIC;
322 }
323
324 // TODO: cache internal names
325 DeclarationDescriptor containing = innerClass.getContainingDeclaration();
326 String outerClassInternalName = containing instanceof ClassDescriptor ? getInternalNameForImpl((ClassDescriptor) containing) : null;
327
328 String innerClassInternalName;
329 String innerName;
330
331 if (isClassObject(innerClass)) {
332 innerName = JvmAbi.CLASS_OBJECT_CLASS_NAME;
333 innerClassInternalName = outerClassInternalName + JvmAbi.CLASS_OBJECT_SUFFIX;
334 }
335 else {
336 innerName = innerClass.getName().isSpecial() ? null : innerClass.getName().asString();
337 innerClassInternalName = getInternalNameForImpl(innerClass);
338 }
339
340 v.visitInnerClass(innerClassInternalName, outerClassInternalName, innerName, innerClassAccess);
341 }
342
343 @NotNull
344 private String getInternalNameForImpl(@NotNull ClassDescriptor descriptor) {
345 return typeMapper.mapType(descriptor.getDefaultType(), JetTypeMapperMode.IMPL).getInternalName();
346 }
347
348 private JvmClassSignature signature() {
349 List<String> superInterfaces;
350
351 LinkedHashSet<String> superInterfacesLinkedHashSet = new LinkedHashSet<String>();
352
353 // TODO: generics signature is not always needed
354 BothSignatureWriter signatureVisitor = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS, true);
355
356
357 { // type parameters
358 List<TypeParameterDescriptor> typeParameters = descriptor.getTypeConstructor().getParameters();
359 typeMapper.writeFormalTypeParameters(typeParameters, signatureVisitor);
360 }
361
362 { // superclass
363 signatureVisitor.writeSuperclass();
364 if (superClassType == null) {
365 signatureVisitor.writeClassBegin(superClassAsmType);
366 signatureVisitor.writeClassEnd();
367 }
368 else {
369 typeMapper.mapType(superClassType, signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER);
370 }
371 signatureVisitor.writeSuperclassEnd();
372 }
373
374
375 { // superinterfaces
376 superInterfacesLinkedHashSet.add(JvmAbi.JET_OBJECT.getInternalName());
377
378 for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) {
379 JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference());
380 assert superType != null;
381 ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
382 if (isInterface(superClassDescriptor)) {
383 signatureVisitor.writeInterface();
384 Type jvmName = typeMapper.mapType(superType, signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER);
385 signatureVisitor.writeInterfaceEnd();
386 superInterfacesLinkedHashSet.add(jvmName.getInternalName());
387 }
388 }
389
390 superInterfaces = new ArrayList<String>(superInterfacesLinkedHashSet);
391 }
392
393 return new JvmClassSignature(classAsmType.getInternalName(), superClassAsmType.getInternalName(), superInterfaces,
394 signatureVisitor.makeJavaGenericSignature());
395 }
396
397 protected void getSuperClass() {
398 superClassAsmType = AsmTypeConstants.OBJECT_TYPE;
399 superClassType = null;
400
401 List<JetDelegationSpecifier> delegationSpecifiers = myClass.getDelegationSpecifiers();
402
403 if (myClass instanceof JetClass && ((JetClass) myClass).isTrait()) {
404 return;
405 }
406
407 if (kind != OwnerKind.IMPLEMENTATION) {
408 throw new IllegalStateException("must be impl to reach this code: " + kind);
409 }
410
411 for (JetDelegationSpecifier specifier : delegationSpecifiers) {
412 if (specifier instanceof JetDelegatorToSuperClass || specifier instanceof JetDelegatorToSuperCall) {
413 JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference());
414 assert superType != null;
415 ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
416 assert superClassDescriptor != null;
417 if (!isInterface(superClassDescriptor)) {
418 superClassType = superType;
419 superClassAsmType = typeMapper.mapType(superClassDescriptor.getDefaultType(), JetTypeMapperMode.IMPL);
420 superCall = specifier;
421 }
422 }
423 }
424
425 if (superClassType == null) {
426 if (descriptor.getKind() == ClassKind.ENUM_CLASS) {
427 superClassType = KotlinBuiltIns.getInstance().getEnumType(descriptor.getDefaultType());
428 superClassAsmType = typeMapper.mapType(superClassType);
429 }
430 if (descriptor.getKind() == ClassKind.ENUM_ENTRY) {
431 superClassType = descriptor.getTypeConstructor().getSupertypes().iterator().next();
432 superClassAsmType = typeMapper.mapType(superClassType);
433 }
434 }
435 }
436
437 @Override
438 protected void generateSyntheticParts() {
439 generateFieldForSingleton();
440
441 generateClassObjectBackingFieldCopies();
442
443 try {
444 generatePrimaryConstructor();
445 }
446 catch (CompilationException e) {
447 throw e;
448 }
449 catch (ProcessCanceledException e) {
450 throw e;
451 }
452 catch (RuntimeException e) {
453 throw new RuntimeException("Error generating primary constructor of class " + myClass.getName() + " with kind " + kind, e);
454 }
455
456 generateTraitMethods();
457
458 generateSyntheticAccessors();
459
460 generateEnumMethodsAndConstInitializers();
461
462 generateFunctionsForDataClasses();
463
464 genClosureFields(context.closure, v, state.getTypeMapper());
465 }
466
467 private List<PropertyDescriptor> getDataProperties() {
468 ArrayList<PropertyDescriptor> result = Lists.newArrayList();
469 for (JetParameter parameter : getPrimaryConstructorParameters()) {
470 if (parameter.getValOrVarNode() == null) continue;
471
472 PropertyDescriptor propertyDescriptor = DescriptorUtils.getPropertyDescriptor(parameter, bindingContext);
473
474 result.add(propertyDescriptor);
475 }
476 return result;
477 }
478
479 private void generateFunctionsForDataClasses() {
480 if (!KotlinBuiltIns.getInstance().isData(descriptor)) return;
481
482 generateComponentFunctionsForDataClasses();
483 generateCopyFunctionForDataClasses();
484
485 List<PropertyDescriptor> properties = getDataProperties();
486 if (!properties.isEmpty()) {
487 generateDataClassToStringIfNeeded(properties);
488 generateDataClassHashCodeIfNeeded(properties);
489 generateDataClassEqualsIfNeeded(properties);
490 }
491 }
492
493 private void generateCopyFunctionForDataClasses() {
494 FunctionDescriptor copyFunction = bindingContext.get(BindingContext.DATA_CLASS_COPY_FUNCTION, descriptor);
495 if (copyFunction != null) {
496 generateCopyFunction(copyFunction);
497 }
498 }
499
500 private void generateDataClassToStringIfNeeded(List<PropertyDescriptor> properties) {
501 ClassDescriptor stringClass = KotlinBuiltIns.getInstance().getString();
502 if (getDeclaredFunctionByRawSignature(descriptor, Name.identifier("toString"), stringClass) == null) {
503 generateDataClassToStringMethod(properties);
504 }
505 }
506
507 private void generateDataClassHashCodeIfNeeded(List<PropertyDescriptor> properties) {
508 ClassDescriptor intClass = KotlinBuiltIns.getInstance().getInt();
509 if (getDeclaredFunctionByRawSignature(descriptor, Name.identifier("hashCode"), intClass) == null) {
510 generateDataClassHashCodeMethod(properties);
511 }
512 }
513
514 private void generateDataClassEqualsIfNeeded(List<PropertyDescriptor> properties) {
515 ClassDescriptor booleanClass = KotlinBuiltIns.getInstance().getBoolean();
516 ClassDescriptor anyClass = KotlinBuiltIns.getInstance().getAny();
517 FunctionDescriptor equalsFunction = getDeclaredFunctionByRawSignature(descriptor, Name.identifier("equals"), booleanClass, anyClass);
518 if (equalsFunction == null) {
519 generateDataClassEqualsMethod(properties);
520 }
521 }
522
523 private void generateDataClassEqualsMethod(List<PropertyDescriptor> properties) {
524 MethodVisitor mv = v.getVisitor().visitMethod(ACC_PUBLIC, "equals", "(Ljava/lang/Object;)Z", null, null);
525 InstructionAdapter iv = new InstructionAdapter(mv);
526
527 mv.visitCode();
528 Label eq = new Label();
529 Label ne = new Label();
530
531 iv.load(0, OBJECT_TYPE);
532 iv.load(1, AsmTypeConstants.OBJECT_TYPE);
533 iv.ifacmpeq(eq);
534
535 iv.load(1, AsmTypeConstants.OBJECT_TYPE);
536 iv.instanceOf(classAsmType);
537 iv.ifeq(ne);
538
539 iv.load(1, AsmTypeConstants.OBJECT_TYPE);
540 iv.checkcast(classAsmType);
541 iv.store(2, AsmTypeConstants.OBJECT_TYPE);
542
543 for (PropertyDescriptor propertyDescriptor : properties) {
544 Type asmType = typeMapper.mapType(propertyDescriptor.getType());
545
546 genPropertyOnStack(iv, propertyDescriptor, 0);
547 genPropertyOnStack(iv, propertyDescriptor, 2);
548
549 if (asmType.getSort() == Type.ARRAY) {
550 Type elementType = correctElementType(asmType);
551 if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
552 iv.invokestatic("java/util/Arrays", "equals", "([Ljava/lang/Object;[Ljava/lang/Object;)Z");
553 }
554 else {
555 iv.invokestatic("java/util/Arrays", "equals", "([" + elementType.getDescriptor() + "[" + elementType.getDescriptor() + ")Z");
556 }
557 }
558 else {
559 StackValue value = genEqualsForExpressionsOnStack(iv, JetTokens.EQEQ, asmType, asmType);
560 value.put(Type.BOOLEAN_TYPE, iv);
561 }
562
563 iv.ifeq(ne);
564 }
565
566 iv.mark(eq);
567 iv.iconst(1);
568 iv.areturn(Type.INT_TYPE);
569
570 iv.mark(ne);
571 iv.iconst(0);
572 iv.areturn(Type.INT_TYPE);
573
574 FunctionCodegen.endVisit(mv, "equals", myClass);
575 }
576
577 private void generateDataClassHashCodeMethod(List<PropertyDescriptor> properties) {
578 MethodVisitor mv = v.getVisitor().visitMethod(ACC_PUBLIC, "hashCode", "()I", null, null);
579 InstructionAdapter iv = new InstructionAdapter(mv);
580
581 mv.visitCode();
582 boolean first = true;
583 for (PropertyDescriptor propertyDescriptor : properties) {
584 if (!first) {
585 iv.iconst(31);
586 iv.mul(Type.INT_TYPE);
587 }
588
589 genPropertyOnStack(iv, propertyDescriptor, 0);
590
591 Label ifNull = null;
592 Type asmType = typeMapper.mapType(propertyDescriptor.getType());
593 if (!isPrimitive(asmType)) {
594 ifNull = new Label();
595 iv.dup();
596 iv.ifnull(ifNull);
597 }
598
599 genHashCode(mv, iv, asmType);
600
601 if (ifNull != null) {
602 Label end = new Label();
603 iv.goTo(end);
604 iv.mark(ifNull);
605 iv.pop();
606 iv.iconst(0);
607 iv.mark(end);
608 }
609
610 if (first) {
611 first = false;
612 }
613 else {
614 iv.add(Type.INT_TYPE);
615 }
616 }
617
618 mv.visitInsn(IRETURN);
619
620 FunctionCodegen.endVisit(mv, "hashCode", myClass);
621 }
622
623 private void generateDataClassToStringMethod(List<PropertyDescriptor> properties) {
624 MethodVisitor mv = v.getVisitor().visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null);
625 InstructionAdapter iv = new InstructionAdapter(mv);
626
627 mv.visitCode();
628 genStringBuilderConstructor(iv);
629
630 boolean first = true;
631 for (PropertyDescriptor propertyDescriptor : properties) {
632 if (first) {
633 iv.aconst(descriptor.getName() + "(" + propertyDescriptor.getName().asString()+"=");
634 first = false;
635 }
636 else {
637 iv.aconst(", " + propertyDescriptor.getName().asString()+"=");
638 }
639 genInvokeAppendMethod(iv, JAVA_STRING_TYPE);
640
641 Type type = genPropertyOnStack(iv, propertyDescriptor, 0);
642
643 if (type.getSort() == Type.ARRAY) {
644 Type elementType = correctElementType(type);
645 if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
646 iv.invokestatic("java/util/Arrays", "toString", "([Ljava/lang/Object;)Ljava/lang/String;");
647 type = JAVA_STRING_TYPE;
648 }
649 else {
650 if (elementType.getSort() != Type.CHAR) {
651 iv.invokestatic("java/util/Arrays", "toString", "(" + type.getDescriptor() + ")Ljava/lang/String;");
652 type = JAVA_STRING_TYPE;
653 }
654 }
655 }
656 genInvokeAppendMethod(iv, type);
657 }
658
659 iv.aconst(")");
660 genInvokeAppendMethod(iv, JAVA_STRING_TYPE);
661
662 iv.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
663 iv.areturn(JAVA_STRING_TYPE);
664
665 FunctionCodegen.endVisit(mv, "toString", myClass);
666 }
667
668 private Type genPropertyOnStack(InstructionAdapter iv, PropertyDescriptor propertyDescriptor, int index) {
669 iv.load(index, classAsmType);
670 Method
671 method = typeMapper.mapGetterSignature(propertyDescriptor, OwnerKind.IMPLEMENTATION).getAsmMethod();
672
673 iv.invokevirtual(classAsmType.getInternalName(), method.getName(), method.getDescriptor());
674 return method.getReturnType();
675 }
676
677 private void generateComponentFunctionsForDataClasses() {
678 if (!myClass.hasPrimaryConstructor() || !KotlinBuiltIns.getInstance().isData(descriptor)) return;
679
680 ConstructorDescriptor constructor = descriptor.getConstructors().iterator().next();
681
682 for (ValueParameterDescriptor parameter : constructor.getValueParameters()) {
683 FunctionDescriptor function = bindingContext.get(BindingContext.DATA_CLASS_COMPONENT_FUNCTION, parameter);
684 if (function != null) {
685 generateComponentFunction(function, parameter);
686 }
687 }
688 }
689
690 private void generateComponentFunction(@NotNull FunctionDescriptor function, @NotNull final ValueParameterDescriptor parameter) {
691 JetType returnType = function.getReturnType();
692 assert returnType != null : "Return type of component function should not be null: " + function;
693 final Type componentType = typeMapper.mapReturnType(returnType);
694
695 JvmMethodSignature signature = typeMapper.mapSignature(function);
696
697 FunctionCodegen fc = new FunctionCodegen(context, v, state);
698 fc.generateMethod(myClass, signature, function, new FunctionGenerationStrategy() {
699 @Override
700 public void generateBody(
701 @NotNull MethodVisitor mv,
702 @NotNull JvmMethodSignature signature,
703 @NotNull MethodContext context
704 ) {
705 InstructionAdapter iv = new InstructionAdapter(mv);
706 if (!componentType.equals(Type.VOID_TYPE)) {
707 iv.load(0, classAsmType);
708 String desc = "()" + componentType.getDescriptor();
709 iv.invokevirtual(classAsmType.getInternalName(), PropertyCodegen.getterName(parameter.getName()), desc);
710 }
711 iv.areturn(componentType);
712 }
713 });
714 }
715
716 private void generateCopyFunction(@NotNull final FunctionDescriptor function) {
717 JvmMethodSignature methodSignature = typeMapper.mapSignature(function);
718
719 final Type thisDescriptorType = typeMapper.mapType(descriptor.getDefaultType());
720
721 FunctionCodegen fc = new FunctionCodegen(context, v, state);
722 fc.generateMethod(myClass, methodSignature, function, new FunctionGenerationStrategy() {
723 @Override
724 public void generateBody(
725 @NotNull MethodVisitor mv,
726 @NotNull JvmMethodSignature signature,
727 @NotNull MethodContext context
728 ) {
729 InstructionAdapter iv = new InstructionAdapter(mv);
730
731 iv.anew(thisDescriptorType);
732 iv.dup();
733
734 ConstructorDescriptor constructor = DescriptorUtils.getConstructorOfDataClass(descriptor);
735 assert function.getValueParameters().size() == constructor.getValueParameters().size() :
736 "Number of parameters of copy function and constructor are different. " +
737 "Copy: " + function.getValueParameters().size() + ", " +
738 "constructor: " + constructor.getValueParameters().size();
739
740 MutableClosure closure = ImplementationBodyCodegen.this.context.closure;
741 if (closure != null && closure.getCaptureThis() != null) {
742 Type type = typeMapper.mapType(enclosingClassDescriptor(bindingContext, descriptor));
743 iv.load(0, classAsmType);
744 iv.getfield(JvmClassName.byType(classAsmType).getInternalName(), CAPTURED_THIS_FIELD, type.getDescriptor());
745 }
746
747 int parameterIndex = 1; // localVariable 0 = this
748 for (ValueParameterDescriptor parameterDescriptor : function.getValueParameters()) {
749 Type type = typeMapper.mapType(parameterDescriptor.getType());
750 iv.load(parameterIndex, type);
751 parameterIndex += type.getSize();
752 }
753
754 String constructorJvmDescriptor = typeMapper.mapToCallableMethod(constructor).getSignature().getAsmMethod().getDescriptor();
755 iv.invokespecial(thisDescriptorType.getInternalName(), "<init>", constructorJvmDescriptor);
756
757 iv.areturn(thisDescriptorType);
758 }
759 });
760
761 MethodContext functionContext = context.intoFunction(function);
762 FunctionCodegen.generateDefaultIfNeeded(functionContext, state, v, methodSignature, function, OwnerKind.IMPLEMENTATION,
763 new DefaultParameterValueLoader() {
764 @Override
765 public void putValueOnStack(
766 ValueParameterDescriptor descriptor,
767 ExpressionCodegen codegen
768 ) {
769 assert (KotlinBuiltIns.getInstance()
770 .isData((ClassDescriptor) function.getContainingDeclaration()))
771 : "Trying to create function with default arguments for function that isn't presented in code for class without data annotation";
772 PropertyDescriptor propertyDescriptor = codegen.getBindingContext().get(
773 BindingContext.VALUE_PARAMETER_AS_PROPERTY, descriptor);
774 assert propertyDescriptor != null
775 : "Trying to generate default value for parameter of copy function that doesn't correspond to any property";
776 codegen.v.load(0, thisDescriptorType);
777 Type propertyType = codegen.typeMapper.mapType(propertyDescriptor.getType());
778 codegen.intermediateValueForProperty(propertyDescriptor, false, null)
779 .put(propertyType, codegen.v);
780 }
781 });
782 }
783
784 private void generateEnumMethodsAndConstInitializers() {
785 if (!myEnumConstants.isEmpty()) {
786 generateEnumMethods();
787
788 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
789 initializeEnumConstants(createOrGetClInitCodegen());
790 }
791 }
792 }
793
794 private void generateEnumMethods() {
795 if (myEnumConstants.size() > 0) {
796 {
797 Type type =
798 typeMapper.mapType(KotlinBuiltIns.getInstance().getArrayType(descriptor.getDefaultType()),
799 JetTypeMapperMode.IMPL);
800
801 MethodVisitor mv =
802 v.newMethod(myClass, ACC_PUBLIC | ACC_STATIC, "values", "()" + type.getDescriptor(), null, null);
803 mv.visitCode();
804 mv.visitFieldInsn(GETSTATIC, typeMapper.mapType(descriptor).getInternalName(),
805 VALUES,
806 type.getDescriptor());
807 mv.visitMethodInsn(INVOKEVIRTUAL, type.getInternalName(), "clone", "()Ljava/lang/Object;");
808 mv.visitTypeInsn(CHECKCAST, type.getInternalName());
809 mv.visitInsn(ARETURN);
810 FunctionCodegen.endVisit(mv, "values()", myClass);
811 }
812 {
813
814 MethodVisitor mv =
815 v.newMethod(myClass, ACC_PUBLIC | ACC_STATIC, "valueOf", "(Ljava/lang/String;)" + classAsmType.getDescriptor(), null,
816 null);
817 mv.visitCode();
818 mv.visitLdcInsn(classAsmType);
819 mv.visitVarInsn(ALOAD, 0);
820 mv.visitMethodInsn(INVOKESTATIC, "java/lang/Enum", "valueOf", "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;");
821 mv.visitTypeInsn(CHECKCAST, classAsmType.getInternalName());
822 mv.visitInsn(ARETURN);
823 FunctionCodegen.endVisit(mv, "values()", myClass);
824 }
825 }
826 }
827
828 protected void generateSyntheticAccessors() {
829 Map<DeclarationDescriptor, DeclarationDescriptor> accessors = context.getAccessors();
830 for (Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry : accessors.entrySet()) {
831 generateSyntheticAccessor(entry);
832 }
833 }
834
835 private void generateSyntheticAccessor(Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry) {
836 if (entry.getValue() instanceof FunctionDescriptor) {
837 FunctionDescriptor bridge = (FunctionDescriptor) entry.getValue();
838 final FunctionDescriptor original = (FunctionDescriptor) entry.getKey();
839 functionCodegen.generateMethod(null, typeMapper.mapSignature(bridge), bridge,
840 new FunctionGenerationStrategy.CodegenBased<FunctionDescriptor>(state, bridge) {
841 @Override
842 public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
843 generateMethodCallTo(original, codegen.v);
844
845 codegen.v.areturn(signature.getAsmMethod().getReturnType());
846 }
847 });
848 }
849 else if (entry.getValue() instanceof PropertyDescriptor) {
850 final PropertyDescriptor bridge = (PropertyDescriptor) entry.getValue();
851 final PropertyDescriptor original = (PropertyDescriptor) entry.getKey();
852
853
854 PropertyGetterDescriptor getter = bridge.getGetter();
855 assert getter != null;
856 functionCodegen.generateMethod(null, typeMapper.mapGetterSignature(bridge, OwnerKind.IMPLEMENTATION), getter,
857 new FunctionGenerationStrategy.CodegenBased<PropertyGetterDescriptor>(state, getter) {
858 @Override
859 public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
860 InstructionAdapter iv = codegen.v;
861 boolean forceField = AsmUtil.isPropertyWithBackingFieldInOuterClass(original) && !isClassObject(bridge.getContainingDeclaration());
862 StackValue property = codegen.intermediateValueForProperty(original, forceField, null, MethodKind.SYNTHETIC_ACCESSOR);
863 if (!forceField) {
864 iv.load(0, OBJECT_TYPE);
865 }
866 property.put(property.type, iv);
867 iv.areturn(signature.getAsmMethod().getReturnType());
868 }
869 });
870
871
872 if (bridge.isVar()) {
873 PropertySetterDescriptor setter = bridge.getSetter();
874 assert setter != null;
875
876 functionCodegen.generateMethod(null, typeMapper.mapSetterSignature(bridge, OwnerKind.IMPLEMENTATION), setter,
877 new FunctionGenerationStrategy.CodegenBased<PropertySetterDescriptor>(state, setter) {
878 @Override
879 public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
880 boolean forceField = AsmUtil.isPropertyWithBackingFieldInOuterClass(original) && !isClassObject(bridge.getContainingDeclaration());
881 StackValue property = codegen.intermediateValueForProperty(original, forceField, null, MethodKind.SYNTHETIC_ACCESSOR);
882 InstructionAdapter iv = codegen.v;
883
884 Type[] argTypes = signature.getAsmMethod().getArgumentTypes();
885 for (int i = 0, reg = 0; i < argTypes.length; i++) {
886 Type argType = argTypes[i];
887 iv.load(reg, argType);
888 //noinspection AssignmentToForLoopParameter
889 reg += argType.getSize();
890 }
891 property.store(property.type, iv);
892
893 iv.areturn(signature.getAsmMethod().getReturnType());
894 }
895 });
896 }
897 }
898 else {
899 throw new UnsupportedOperationException();
900 }
901 }
902
903 private void generateMethodCallTo(FunctionDescriptor functionDescriptor, InstructionAdapter iv) {
904 boolean isConstructor = functionDescriptor instanceof ConstructorDescriptor;
905 boolean callFromAccessor = !JetTypeMapper.isAccessor(functionDescriptor);
906 CallableMethod callableMethod = isConstructor ?
907 typeMapper.mapToCallableMethod((ConstructorDescriptor) functionDescriptor) :
908 typeMapper.mapToCallableMethod(functionDescriptor, callFromAccessor,
909 isCallInsideSameClassAsDeclared(functionDescriptor, context),
910 isCallInsideSameModuleAsDeclared(functionDescriptor, context),
911 context.getContextKind());
912
913 Method method = callableMethod.getSignature().getAsmMethod();
914 Type[] argTypes = method.getArgumentTypes();
915
916 int reg = 1;
917 if (isConstructor) {
918 iv.anew(callableMethod.getOwner().getAsmType());
919 iv.dup();
920 reg = 0;
921 }
922 else if (callFromAccessor) {
923 iv.load(0, OBJECT_TYPE);
924 }
925
926 for (int paramIndex = 0; paramIndex < argTypes.length; paramIndex++) {
927 Type argType = argTypes[paramIndex];
928 iv.load(reg, argType);
929 //noinspection AssignmentToForLoopParameter
930 reg += argType.getSize();
931 }
932 callableMethod.invokeWithoutAssertions(iv);
933 }
934
935 private void generateFieldForSingleton() {
936 boolean hasClassObject = descriptor.getClassObjectDescriptor() != null;
937 boolean isEnumClass = DescriptorUtils.isEnumClass(descriptor);
938 boolean isObjectDeclaration = descriptor.getKind() == ClassKind.OBJECT && isNonLiteralObject(myClass) ;
939
940 if (!isObjectDeclaration && !hasClassObject || isEnumClass) return;
941
942 ClassDescriptor fieldTypeDescriptor = hasClassObject ? descriptor.getClassObjectDescriptor() : descriptor;
943 assert fieldTypeDescriptor != null;
944 StackValue.Field field = StackValue.singleton(fieldTypeDescriptor, typeMapper);
945 JetClassOrObject original;
946 if (hasClassObject) {
947 JetClassObject classObject = ((JetClass) myClass).getClassObject();
948 assert classObject != null : myClass.getText();
949 original = classObject.getObjectDeclaration();
950 }
951 else {
952 original = myClass;
953 }
954
955 v.newField(original, ACC_PUBLIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null);
956
957 if (!AsmUtil.isClassObjectWithBackingFieldsInOuter(fieldTypeDescriptor)) {
958 genInitSingleton(fieldTypeDescriptor, field);
959 }
960 }
961
962 private void generateClassObjectBackingFieldCopies() {
963 if (classObjectPropertiesToCopy != null) {
964 for (PropertyAndDefaultValue propertyInfo : classObjectPropertiesToCopy) {
965 PropertyDescriptor propertyDescriptor = propertyInfo.propertyDescriptor;
966
967 v.newField(null, ACC_STATIC | ACC_FINAL | ACC_PUBLIC, context.getFieldName(propertyDescriptor),
968 typeMapper.mapType(propertyDescriptor).getDescriptor(), null, propertyInfo.defaultValue);
969
970 //This field are always static and final so if it has constant initializer don't do anything in clinit,
971 //field would be initialized via default value in v.newField(...) - see JVM SPEC Ch.4
972 if (state.getClassBuilderMode() == ClassBuilderMode.FULL && propertyInfo.defaultValue == null) {
973 ExpressionCodegen codegen = createOrGetClInitCodegen();
974 int classObjectIndex = putClassObjectInLocalVar(codegen);
975 StackValue.local(classObjectIndex, OBJECT_TYPE).put(OBJECT_TYPE, codegen.v);
976 copyFieldFromClassObject(propertyDescriptor);
977 }
978 }
979 }
980 }
981
982 private int putClassObjectInLocalVar(ExpressionCodegen codegen) {
983 FrameMap frameMap = codegen.myFrameMap;
984 ClassDescriptor classObjectDescriptor = descriptor.getClassObjectDescriptor();
985 int classObjectIndex = frameMap.getIndex(classObjectDescriptor);
986 if (classObjectIndex == -1) {
987 classObjectIndex = frameMap.enter(classObjectDescriptor, OBJECT_TYPE);
988 StackValue classObject = StackValue.singleton(classObjectDescriptor, typeMapper);
989 classObject.put(classObject.type, codegen.v);
990 StackValue.local(classObjectIndex, classObject.type).store(classObject.type, codegen.v);
991 }
992 return classObjectIndex;
993 }
994
995 private void copyFieldFromClassObject(PropertyDescriptor propertyDescriptor) {
996 ExpressionCodegen codegen = createOrGetClInitCodegen();
997 StackValue property = codegen.intermediateValueForProperty(propertyDescriptor, false, null);
998 property.put(property.type, codegen.v);
999 StackValue.Field field = StackValue.field(property.type, JvmClassName.byClassDescriptor(descriptor),
1000 propertyDescriptor.getName().asString(), true);
1001 field.store(field.type, codegen.v);
1002 }
1003
1004 protected void genInitSingleton(ClassDescriptor fieldTypeDescriptor, StackValue.Field field) {
1005 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
1006 ConstructorDescriptor constructorDescriptor = DescriptorUtils.getConstructorOfSingletonObject(fieldTypeDescriptor);
1007 ExpressionCodegen codegen = createOrGetClInitCodegen();
1008 FunctionDescriptor fd = codegen.accessibleFunctionDescriptor(constructorDescriptor);
1009 generateMethodCallTo(fd, codegen.v);
1010 field.store(field.type, codegen.v);
1011 }
1012 }
1013
1014 protected void generatePrimaryConstructor() {
1015 if (ignoreIfTraitOrAnnotation()) return;
1016
1017 if (kind != OwnerKind.IMPLEMENTATION) {
1018 throw new IllegalStateException("incorrect kind for primary constructor: " + kind);
1019 }
1020
1021 final MutableClosure closure = context.closure;
1022 ConstructorDescriptor constructorDescriptor = bindingContext.get(BindingContext.CONSTRUCTOR, myClass);
1023
1024 ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor);
1025
1026 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
1027 lookupConstructorExpressionsInClosureIfPresent(constructorContext);
1028 }
1029
1030 assert constructorDescriptor != null;
1031 final JvmMethodSignature constructorSignature = typeMapper.mapConstructorSignature(constructorDescriptor, closure);
1032
1033 functionCodegen.generateMethod(null, constructorSignature, constructorDescriptor, constructorContext,
1034 new FunctionGenerationStrategy.CodegenBased<ConstructorDescriptor>(state, constructorDescriptor) {
1035
1036 @NotNull
1037 @Override
1038 protected FrameMap createFrameMap(@NotNull JetTypeMapper typeMapper, @NotNull MethodContext context) {
1039 return new ConstructorFrameMap(constructorSignature);
1040 }
1041
1042 @Override
1043 public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
1044 generatePrimaryConstructorImpl(callableDescriptor, codegen, closure);
1045 }
1046 }
1047 );
1048
1049 FunctionCodegen.generateDefaultIfNeeded(constructorContext, state, v, constructorSignature, constructorDescriptor,
1050 OwnerKind.IMPLEMENTATION, DefaultParameterValueLoader.DEFAULT);
1051
1052 CallableMethod callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor, closure);
1053 FunctionCodegen.generateConstructorWithoutParametersIfNeeded(state, callableMethod, constructorDescriptor, v);
1054
1055 if (isClassObject(descriptor)) {
1056 context.recordSyntheticAccessorIfNeeded(constructorDescriptor, typeMapper);
1057 }
1058 }
1059
1060 private void generatePrimaryConstructorImpl(
1061 @Nullable ConstructorDescriptor constructorDescriptor,
1062 @NotNull ExpressionCodegen codegen,
1063 @Nullable MutableClosure closure
1064 ) {
1065 List<ValueParameterDescriptor> paramDescrs = constructorDescriptor != null
1066 ? constructorDescriptor.getValueParameters()
1067 : Collections.<ValueParameterDescriptor>emptyList();
1068
1069 InstructionAdapter iv = codegen.v;
1070
1071 JvmClassName className = JvmClassName.byType(classAsmType);
1072
1073 if (superCall == null) {
1074 genSimpleSuperCall(iv);
1075 }
1076 else if (superCall instanceof JetDelegatorToSuperClass) {
1077 genSuperCallToDelegatorToSuperClass(iv);
1078 }
1079 else {
1080 generateDelegatorToConstructorCall(iv, codegen, constructorDescriptor);
1081 }
1082
1083 if (closure != null) {
1084 List<FieldInfo> argsFromClosure = ClosureCodegen.calculateConstructorParameters(typeMapper, closure, classAsmType);
1085 int k = 1;
1086 for (FieldInfo info : argsFromClosure) {
1087 k = AsmUtil.genAssignInstanceFieldFromParam(info, k, iv);
1088 }
1089 }
1090
1091 int n = 0;
1092 for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) {
1093 if (specifier == superCall) {
1094 continue;
1095 }
1096
1097 if (specifier instanceof JetDelegatorByExpressionSpecifier) {
1098 genCallToDelegatorByExpressionSpecifier(iv, codegen, classAsmType, className, n++, specifier);
1099 }
1100 }
1101
1102 int curParam = 0;
1103 List<JetParameter> constructorParameters = getPrimaryConstructorParameters();
1104 for (JetParameter parameter : constructorParameters) {
1105 if (parameter.getValOrVarNode() != null) {
1106 VariableDescriptor descriptor = paramDescrs.get(curParam);
1107 Type type = typeMapper.mapType(descriptor);
1108 iv.load(0, classAsmType);
1109 iv.load(codegen.myFrameMap.getIndex(descriptor), type);
1110 iv.putfield(classAsmType.getInternalName(),
1111 context.getFieldName(DescriptorUtils.getPropertyDescriptor(parameter, bindingContext)),
1112 type.getDescriptor());
1113 }
1114 curParam++;
1115 }
1116
1117 boolean generateInitializerInOuter = isClassObjectWithBackingFieldsInOuter(descriptor);
1118 if (generateInitializerInOuter) {
1119 ImplementationBodyCodegen parentCodegen = getParentBodyCodegen(this);
1120 //generate object$
1121 parentCodegen.genInitSingleton(descriptor, StackValue.singleton(descriptor, typeMapper));
1122 parentCodegen.generateInitializers(parentCodegen.createOrGetClInitCodegen(),
1123 myClass.getDeclarations(), bindingContext, state);
1124 } else {
1125 generateInitializers(codegen, myClass.getDeclarations(), bindingContext, state);
1126 }
1127
1128
1129 iv.visitInsn(RETURN);
1130 }
1131
1132 private void genSuperCallToDelegatorToSuperClass(InstructionAdapter iv) {
1133 iv.load(0, superClassAsmType);
1134 JetType superType = bindingContext.get(BindingContext.TYPE, superCall.getTypeReference());
1135 List<Type> parameterTypes = new ArrayList<Type>();
1136 assert superType != null;
1137 ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
1138 if (CodegenBinding.hasThis0(bindingContext, superClassDescriptor)) {
1139 iv.load(1, OBJECT_TYPE);
1140 parameterTypes.add(typeMapper.mapType(
1141 enclosingClassDescriptor(bindingContext, descriptor)));
1142 }
1143 Method superCallMethod = new Method("<init>", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()]));
1144 //noinspection ConstantConditions
1145 iv.invokespecial(typeMapper.mapType(superClassDescriptor).getInternalName(), "<init>",
1146 superCallMethod.getDescriptor());
1147 }
1148
1149 private void genSimpleSuperCall(InstructionAdapter iv) {
1150 iv.load(0, superClassAsmType);
1151 if (descriptor.getKind() == ClassKind.ENUM_CLASS || descriptor.getKind() == ClassKind.ENUM_ENTRY) {
1152 iv.load(1, JAVA_STRING_TYPE);
1153 iv.load(2, Type.INT_TYPE);
1154 iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "(Ljava/lang/String;I)V");
1155 }
1156 else {
1157 iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "()V");
1158 }
1159 }
1160
1161 private void genCallToDelegatorByExpressionSpecifier(
1162 InstructionAdapter iv,
1163 ExpressionCodegen codegen,
1164 Type classType,
1165 JvmClassName className,
1166 int n,
1167 JetDelegationSpecifier specifier
1168 ) {
1169 JetExpression expression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression();
1170 PropertyDescriptor propertyDescriptor = null;
1171 if (expression instanceof JetSimpleNameExpression) {
1172 ResolvedCall<? extends CallableDescriptor> call = bindingContext.get(BindingContext.RESOLVED_CALL, expression);
1173 if (call != null) {
1174 CallableDescriptor callResultingDescriptor = call.getResultingDescriptor();
1175 if (callResultingDescriptor instanceof ValueParameterDescriptor) {
1176 ValueParameterDescriptor valueParameterDescriptor = (ValueParameterDescriptor) callResultingDescriptor;
1177 // constructor parameter
1178 if (valueParameterDescriptor.getContainingDeclaration() instanceof ConstructorDescriptor) {
1179 // constructor of my class
1180 if (valueParameterDescriptor.getContainingDeclaration().getContainingDeclaration() == descriptor) {
1181 propertyDescriptor = bindingContext.get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, valueParameterDescriptor);
1182 }
1183 }
1184 }
1185
1186 // todo: when and if frontend will allow properties defined not as constructor parameters to be used in delegation specifier
1187 }
1188 }
1189
1190 JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference());
1191 assert superType != null;
1192
1193 ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
1194 assert superClassDescriptor != null;
1195
1196 StackValue field;
1197 if (propertyDescriptor != null &&
1198 !propertyDescriptor.isVar() &&
1199 Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor))) {
1200 // final property with backing field
1201 field = StackValue.field(typeMapper.mapType(propertyDescriptor.getType()), className,
1202 propertyDescriptor.getName().asString(), false);
1203 }
1204 else {
1205 iv.load(0, classType);
1206 codegen.genToJVMStack(expression);
1207
1208 String delegateField = "$delegate_" + n;
1209 Type fieldType = typeMapper.mapType(superClassDescriptor);
1210 String fieldDesc = fieldType.getDescriptor();
1211
1212 v.newField(specifier, ACC_PRIVATE|ACC_FINAL|ACC_SYNTHETIC, delegateField, fieldDesc, /*TODO*/null, null);
1213
1214 field = StackValue.field(fieldType, className, delegateField, false);
1215 field.store(fieldType, iv);
1216 }
1217
1218 generateDelegates(superClassDescriptor, field);
1219 }
1220
1221 private void lookupConstructorExpressionsInClosureIfPresent(final ConstructorContext constructorContext) {
1222 JetVisitorVoid visitor = new JetVisitorVoid() {
1223 @Override
1224 public void visitJetElement(JetElement e) {
1225 e.acceptChildren(this);
1226 }
1227
1228 @Override
1229 public void visitSimpleNameExpression(JetSimpleNameExpression expr) {
1230 DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expr);
1231 if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) {
1232 ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) constructorContext.getContextDescriptor();
1233 for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
1234 //noinspection ConstantConditions
1235 if (descriptor.equals(parameterDescriptor)) {
1236 return;
1237 }
1238 }
1239 constructorContext.lookupInContext(descriptor, null, state, true);
1240 } else if (isLocalNamedFun(descriptor)) {
1241 assert descriptor != null;
1242 MutableClassDescriptor classDescriptor =
1243 (MutableClassDescriptor) constructorContext.getParentContext().getContextDescriptor();
1244
1245 for (CallableMemberDescriptor memberDescriptor : classDescriptor.getAllCallableMembers()) {
1246 if (descriptor.equals(memberDescriptor)) {
1247 return;
1248 }
1249 }
1250 constructorContext.lookupInContext(descriptor, null, state, true);
1251 }
1252 }
1253
1254 @Override
1255 public void visitThisExpression(JetThisExpression expression) {
1256 DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference());
1257 if (descriptor instanceof ClassDescriptor) {
1258 // @todo for now all our classes are inner so no need to lookup this. change it when we have real inners
1259 }
1260 else {
1261 assert descriptor instanceof CallableDescriptor;
1262 if (context.getCallableDescriptorWithReceiver() != descriptor) {
1263 context.lookupInContext(descriptor, null, state, false);
1264 }
1265 }
1266 }
1267 };
1268
1269 for (JetDeclaration declaration : myClass.getDeclarations()) {
1270 if (declaration instanceof JetProperty) {
1271 JetProperty property = (JetProperty) declaration;
1272 JetExpression initializer = property.getInitializer();
1273 if (initializer != null) {
1274 initializer.accept(visitor);
1275 }
1276 }
1277 else if (declaration instanceof JetClassInitializer) {
1278 JetClassInitializer initializer = (JetClassInitializer) declaration;
1279 initializer.accept(visitor);
1280 }
1281 }
1282
1283 for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) {
1284 if (specifier != superCall) {
1285 if (specifier instanceof JetDelegatorByExpressionSpecifier) {
1286 JetExpression delegateExpression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression();
1287 assert delegateExpression != null;
1288 delegateExpression.accept(visitor);
1289 }
1290 }
1291 else {
1292 if (superCall instanceof JetDelegatorToSuperCall) {
1293 JetValueArgumentList argumentList = ((JetDelegatorToSuperCall) superCall).getValueArgumentList();
1294 if (argumentList != null) {
1295 argumentList.accept(visitor);
1296 }
1297 }
1298 }
1299 }
1300 }
1301
1302 private boolean ignoreIfTraitOrAnnotation() {
1303 if (myClass instanceof JetClass) {
1304 JetClass aClass = (JetClass) myClass;
1305 if (aClass.isTrait()) {
1306 return true;
1307 }
1308 if (aClass.isAnnotation()) {
1309 return true;
1310 }
1311 }
1312 return false;
1313 }
1314
1315 private void generateTraitMethods() {
1316 if (JetPsiUtil.isTrait(myClass)) {
1317 return;
1318 }
1319
1320 for (Pair<CallableMemberDescriptor, CallableMemberDescriptor> needDelegates : getTraitImplementations(descriptor)) {
1321 if (needDelegates.second instanceof SimpleFunctionDescriptor) {
1322 generateDelegationToTraitImpl((FunctionDescriptor) needDelegates.second, (FunctionDescriptor) needDelegates.first);
1323 }
1324 else if (needDelegates.second instanceof PropertyDescriptor) {
1325 PropertyDescriptor property = (PropertyDescriptor) needDelegates.second;
1326 List<PropertyAccessorDescriptor> inheritedAccessors = ((PropertyDescriptor) needDelegates.first).getAccessors();
1327 for (PropertyAccessorDescriptor accessor : property.getAccessors()) {
1328 for (PropertyAccessorDescriptor inheritedAccessor : inheritedAccessors) {
1329 if (inheritedAccessor.getClass() == accessor.getClass()) { // same accessor kind
1330 generateDelegationToTraitImpl(accessor, inheritedAccessor);
1331 }
1332 }
1333 }
1334 }
1335 }
1336 }
1337
1338
1339 private void generateDelegationToTraitImpl(final @NotNull FunctionDescriptor fun, @NotNull FunctionDescriptor inheritedFun) {
1340 DeclarationDescriptor containingDeclaration = fun.getContainingDeclaration();
1341 if (!(containingDeclaration instanceof ClassDescriptor)) {
1342 return;
1343 }
1344
1345 ClassDescriptor containingClass = (ClassDescriptor) containingDeclaration;
1346 if (containingClass.getKind() != ClassKind.TRAIT) {
1347 return;
1348 }
1349
1350 int flags = ACC_PUBLIC; // TODO.
1351
1352 TraitImplDelegateInfo delegateInfo = getTraitImplDelegateInfo(fun);
1353 Method methodToGenerate = delegateInfo.methodToGenerate;
1354 Method methodInTrait = delegateInfo.methodInTrait;
1355
1356 PsiElement origin = descriptorToDeclaration(bindingContext, fun);
1357 MethodVisitor mv = v.newMethod(origin, flags, methodToGenerate.getName(), methodToGenerate.getDescriptor(), null, null);
1358 AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(fun);
1359
1360 if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
1361 genStubCode(mv);
1362 }
1363 else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
1364 Type returnType = methodToGenerate.getReturnType();
1365
1366 mv.visitCode();
1367 FrameMap frameMap = context.prepareFrame(typeMapper);
1368 ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, returnType, context.intoFunction(inheritedFun), state);
1369 codegen.generateThisOrOuter(descriptor, false); // ??? wouldn't it be addClosureToConstructorParameters good idea to put it?
1370
1371 Type[] argTypes = methodToGenerate.getArgumentTypes();
1372 Type[] originalArgTypes = methodInTrait.getArgumentTypes();
1373
1374 InstructionAdapter iv = new InstructionAdapter(mv);
1375 iv.load(0, OBJECT_TYPE);
1376 for (int i = 0, reg = 1; i < argTypes.length; i++) {
1377 StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
1378 //noinspection AssignmentToForLoopParameter
1379 reg += argTypes[i].getSize();
1380 }
1381
1382 Type type = getTraitImplThisParameterType(containingClass, typeMapper);
1383 String functionDescriptor = methodInTrait.getDescriptor().replace("(", "(" + type.getDescriptor());
1384
1385 Type tImplType = typeMapper.mapType(containingClass.getDefaultType(), JetTypeMapperMode.TRAIT_IMPL);
1386
1387 iv.invokestatic(tImplType.getInternalName(), methodToGenerate.getName(), functionDescriptor);
1388 StackValue.onStack(methodInTrait.getReturnType()).put(returnType, iv);
1389 iv.areturn(returnType);
1390
1391 FunctionCodegen.endVisit(iv, "trait method", callableDescriptorToDeclaration(bindingContext, fun));
1392 }
1393
1394 FunctionCodegen.generateBridgeIfNeeded(context, state, v, methodToGenerate, fun);
1395 }
1396
1397 private static class TraitImplDelegateInfo {
1398 private final Method methodToGenerate;
1399 private final Method methodInTrait;
1400
1401 private TraitImplDelegateInfo(@NotNull Method methodToGenerate, @NotNull Method methodInTrait) {
1402 this.methodToGenerate = methodToGenerate;
1403 this.methodInTrait = methodInTrait;
1404 }
1405 }
1406
1407 @NotNull
1408 private TraitImplDelegateInfo getTraitImplDelegateInfo(@NotNull FunctionDescriptor fun) {
1409 if (fun instanceof PropertyAccessorDescriptor) {
1410 PropertyDescriptor property = ((PropertyAccessorDescriptor) fun).getCorrespondingProperty();
1411 PropertyDescriptor original = property.getOriginal();
1412 if (fun instanceof PropertyGetterDescriptor) {
1413 JvmMethodSignature toGenerate = typeMapper.mapGetterSignature(property, OwnerKind.IMPLEMENTATION);
1414 JvmMethodSignature inTrait = typeMapper.mapGetterSignature(original, OwnerKind.IMPLEMENTATION);
1415 return new TraitImplDelegateInfo(
1416 toGenerate.getAsmMethod(), inTrait.getAsmMethod());
1417 }
1418 else if (fun instanceof PropertySetterDescriptor) {
1419 JvmMethodSignature toGenerate = typeMapper.mapSetterSignature(property, OwnerKind.IMPLEMENTATION);
1420 JvmMethodSignature inTrait = typeMapper.mapSetterSignature(original, OwnerKind.IMPLEMENTATION);
1421 return new TraitImplDelegateInfo(
1422 toGenerate.getAsmMethod(), inTrait.getAsmMethod());
1423 }
1424 else {
1425 throw new IllegalStateException("Accessor is neither getter, nor setter, what is it? " + fun);
1426 }
1427 }
1428 else {
1429 Method function = typeMapper.mapSignature(fun).getAsmMethod();
1430 Method functionOriginal = typeMapper.mapSignature(fun.getOriginal()).getAsmMethod();
1431 return new TraitImplDelegateInfo(function, functionOriginal);
1432 }
1433 }
1434
1435 private void generateDelegatorToConstructorCall(
1436 InstructionAdapter iv, ExpressionCodegen codegen,
1437 ConstructorDescriptor constructorDescriptor
1438 ) {
1439 ClassDescriptor classDecl = constructorDescriptor.getContainingDeclaration();
1440
1441 iv.load(0, OBJECT_TYPE);
1442
1443 if (classDecl.getKind() == ClassKind.ENUM_CLASS || classDecl.getKind() == ClassKind.ENUM_ENTRY) {
1444 iv.load(1, OBJECT_TYPE);
1445 iv.load(2, Type.INT_TYPE);
1446 }
1447
1448 CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor, context.closure);
1449
1450 ResolvedCall<? extends CallableDescriptor> resolvedCall =
1451 bindingContext.get(BindingContext.RESOLVED_CALL, ((JetCallElement) superCall).getCalleeExpression());
1452 assert resolvedCall != null;
1453 ConstructorDescriptor superConstructor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor();
1454
1455 //noinspection SuspiciousMethodCalls
1456 CalculatedClosure closureForSuper = bindingContext.get(CLOSURE, superConstructor.getContainingDeclaration());
1457 CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor, closureForSuper);
1458
1459 if (closureForSuper != null && closureForSuper.getCaptureThis() != null) {
1460 iv.load(((ConstructorFrameMap)codegen.myFrameMap).getOuterThisIndex(), OBJECT_TYPE);
1461 }
1462
1463 if (myClass instanceof JetObjectDeclaration &&
1464 superCall instanceof JetDelegatorToSuperCall &&
1465 ((JetObjectDeclaration) myClass).isObjectLiteral()) {
1466 int nextVar = findFirstSuperArgument(method);
1467 for (Type t : superCallable.getSignature().getAsmMethod().getArgumentTypes()) {
1468 iv.load(nextVar, t);
1469 nextVar += t.getSize();
1470 }
1471 superCallable.invokeWithNotNullAssertion(codegen.v, state, resolvedCall);
1472 }
1473 else {
1474 codegen.invokeMethodWithArguments(superCallable, resolvedCall, null, StackValue.none());
1475 }
1476 }
1477
1478 private static int findFirstSuperArgument(CallableMethod method) {
1479 List<JvmMethodParameterSignature> types = method.getSignature().getKotlinParameterTypes();
1480 int i = 0;
1481 for (JvmMethodParameterSignature type : types) {
1482 if (type.getKind() == JvmMethodParameterKind.SUPER_CALL_PARAM) {
1483 return i + 1; // because of this
1484 }
1485 i += type.getAsmType().getSize();
1486 }
1487 return -1;
1488 }
1489
1490 @Override
1491 protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration) {
1492 if (declaration instanceof JetEnumEntry) {
1493 String name = declaration.getName();
1494 assert name != null : "Enum entry has no name: " + declaration.getText();
1495 String desc = "L" + classAsmType.getInternalName() + ";";
1496 v.newField(declaration, ACC_PUBLIC | ACC_ENUM | ACC_STATIC | ACC_FINAL, name, desc, null, null);
1497 myEnumConstants.add((JetEnumEntry) declaration);
1498 }
1499
1500 super.generateDeclaration(propertyCodegen, declaration);
1501 }
1502
1503 private final List<JetEnumEntry> myEnumConstants = new ArrayList<JetEnumEntry>();
1504
1505 private void initializeEnumConstants(ExpressionCodegen codegen) {
1506 InstructionAdapter iv = codegen.v;
1507 int ordinal = -1;
1508 JetType myType = descriptor.getDefaultType();
1509 Type myAsmType = typeMapper.mapType(myType, JetTypeMapperMode.IMPL);
1510
1511 assert myEnumConstants.size() > 0;
1512 JetType arrayType = KotlinBuiltIns.getInstance().getArrayType(myType);
1513 Type arrayAsmType = typeMapper.mapType(arrayType, JetTypeMapperMode.IMPL);
1514 v.newField(myClass, ACC_PRIVATE | ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, "$VALUES", arrayAsmType.getDescriptor(), null, null);
1515
1516 iv.iconst(myEnumConstants.size());
1517 iv.newarray(myAsmType);
1518 iv.dup();
1519
1520 for (JetEnumEntry enumConstant : myEnumConstants) {
1521 ordinal++;
1522
1523 iv.dup();
1524 iv.iconst(ordinal);
1525
1526 ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, enumConstant);
1527 assert classDescriptor != null;
1528 String implClass = typeMapper.mapType(classDescriptor.getDefaultType(), JetTypeMapperMode.IMPL).getInternalName();
1529
1530 List<JetDelegationSpecifier> delegationSpecifiers = enumConstant.getDelegationSpecifiers();
1531 if (delegationSpecifiers.size() > 1) {
1532 throw new UnsupportedOperationException("multiple delegation specifiers for enum constant not supported");
1533 }
1534
1535 iv.anew(Type.getObjectType(implClass));
1536 iv.dup();
1537
1538 iv.aconst(enumConstant.getName());
1539 iv.iconst(ordinal);
1540
1541 if (delegationSpecifiers.size() == 1 && !enumEntryNeedSubclass(state.getBindingContext(), enumConstant)) {
1542 JetDelegationSpecifier specifier = delegationSpecifiers.get(0);
1543 if (specifier instanceof JetDelegatorToSuperCall) {
1544 ResolvedCall<? extends CallableDescriptor> resolvedCall =
1545 bindingContext.get(BindingContext.RESOLVED_CALL, ((JetDelegatorToSuperCall) specifier).getCalleeExpression());
1546 assert resolvedCall != null : "Enum entry delegation specifier is unresolved: " + specifier.getText();
1547
1548 ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor();
1549 CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor);
1550
1551 codegen.invokeMethodWithArguments(method, resolvedCall, null, StackValue.none());
1552 }
1553 else {
1554 throw new UnsupportedOperationException("unsupported type of enum constant initializer: " + specifier);
1555 }
1556 }
1557 else {
1558 iv.invokespecial(implClass, "<init>", "(Ljava/lang/String;I)V");
1559 }
1560 iv.dup();
1561 iv.putstatic(myAsmType.getInternalName(), enumConstant.getName(), "L" + myAsmType.getInternalName() + ";");
1562 iv.astore(OBJECT_TYPE);
1563 }
1564 iv.putstatic(myAsmType.getInternalName(), "$VALUES", arrayAsmType.getDescriptor());
1565 }
1566
1567 public static void generateInitializers(
1568 @NotNull ExpressionCodegen codegen, @NotNull List<JetDeclaration> declarations,
1569 @NotNull BindingContext bindingContext, @NotNull GenerationState state
1570 ) {
1571 JetTypeMapper typeMapper = state.getTypeMapper();
1572 for (JetDeclaration declaration : declarations) {
1573 if (declaration instanceof JetProperty) {
1574 if (shouldInitializeProperty((JetProperty) declaration, typeMapper)) {
1575 initializeProperty(codegen, bindingContext, (JetProperty) declaration);
1576 }
1577 }
1578 else if (declaration instanceof JetClassInitializer) {
1579 codegen.gen(((JetClassInitializer) declaration).getBody(), Type.VOID_TYPE);
1580 }
1581 }
1582 }
1583
1584
1585 public static void initializeProperty(
1586 @NotNull ExpressionCodegen codegen,
1587 @NotNull BindingContext bindingContext,
1588 @NotNull JetProperty property
1589 ) {
1590
1591 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(BindingContext.VARIABLE, property);
1592 assert propertyDescriptor != null;
1593
1594 JetExpression initializer = property.getDelegateExpressionOrInitializer();
1595 assert initializer != null : "shouldInitializeProperty must return false if initializer is null";
1596
1597 JetType jetType = getPropertyOrDelegateType(bindingContext, property, propertyDescriptor);
1598
1599 StackValue.StackValueWithSimpleReceiver propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, null, MethodKind.INITIALIZER);
1600
1601 if (!propValue.isStatic) {
1602 codegen.v.load(0, OBJECT_TYPE);
1603 }
1604
1605 Type type = codegen.expressionType(initializer);
1606 if (jetType.isNullable()) {
1607 type = boxType(type);
1608 }
1609 codegen.gen(initializer, type);
1610
1611 propValue.store(type, codegen.v);
1612 }
1613
1614 public static boolean shouldWriteFieldInitializer(PropertyDescriptor descriptor, JetTypeMapper mapper) {
1615 //final field of primitive or String type
1616 if (!descriptor.isVar()) {
1617 Type type = mapper.mapType(descriptor.getType());
1618 return AsmUtil.isPrimitive(type) || "java.lang.String".equals(type.getClassName());
1619 }
1620 return false;
1621 }
1622
1623 public static boolean shouldInitializeProperty(
1624 @NotNull JetProperty property,
1625 @NotNull JetTypeMapper typeMapper
1626 ) {
1627 JetExpression initializer = property.getDelegateExpressionOrInitializer();
1628 if (initializer == null) return false;
1629
1630 CompileTimeConstant<?> compileTimeValue = typeMapper.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, initializer);
1631 if (compileTimeValue == null) return true;
1632
1633 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) typeMapper.getBindingContext().get(BindingContext.VARIABLE, property);
1634 assert propertyDescriptor != null;
1635
1636 //TODO: OPTIMIZATION: don't initialize static final fields
1637
1638 Object value = compileTimeValue.getValue();
1639 JetType jetType = getPropertyOrDelegateType(typeMapper.getBindingContext(), property, propertyDescriptor);
1640 Type type = typeMapper.mapType(jetType);
1641 return !skipDefaultValue(propertyDescriptor, value, type);
1642 }
1643
1644 @NotNull
1645 private static JetType getPropertyOrDelegateType(@NotNull BindingContext bindingContext, @NotNull JetProperty property, @NotNull PropertyDescriptor descriptor) {
1646 JetExpression delegateExpression = property.getDelegateExpression();
1647 if (delegateExpression != null) {
1648 JetType delegateType = bindingContext.get(BindingContext.EXPRESSION_TYPE, delegateExpression);
1649 assert delegateType != null : "Type of delegate expression should be recorded";
1650 return delegateType;
1651 }
1652 return descriptor.getType();
1653 }
1654
1655 private static boolean skipDefaultValue(@NotNull PropertyDescriptor propertyDescriptor, Object value, @NotNull Type type) {
1656 if (isPrimitive(type)) {
1657 if (!propertyDescriptor.getType().isNullable() && value instanceof Number) {
1658 if (type == Type.INT_TYPE && ((Number) value).intValue() == 0) {
1659 return true;
1660 }
1661 if (type == Type.BYTE_TYPE && ((Number) value).byteValue() == 0) {
1662 return true;
1663 }
1664 if (type == Type.LONG_TYPE && ((Number) value).longValue() == 0L) {
1665 return true;
1666 }
1667 if (type == Type.SHORT_TYPE && ((Number) value).shortValue() == 0) {
1668 return true;
1669 }
1670 if (type == Type.DOUBLE_TYPE && ((Number) value).doubleValue() == 0d) {
1671 return true;
1672 }
1673 if (type == Type.FLOAT_TYPE && ((Number) value).floatValue() == 0f) {
1674 return true;
1675 }
1676 }
1677 if (type == Type.BOOLEAN_TYPE && value instanceof Boolean && !((Boolean) value)) {
1678 return true;
1679 }
1680 if (type == Type.CHAR_TYPE && value instanceof Character && ((Character) value) == 0) {
1681 return true;
1682 }
1683 }
1684 else {
1685 if (value == null) {
1686 return true;
1687 }
1688 }
1689 return false;
1690 }
1691
1692 protected void generateDelegates(ClassDescriptor toClass, StackValue field) {
1693 for (DeclarationDescriptor declaration : descriptor.getDefaultType().getMemberScope().getAllDescriptors()) {
1694 if (declaration instanceof CallableMemberDescriptor) {
1695 CallableMemberDescriptor callableMemberDescriptor = (CallableMemberDescriptor) declaration;
1696 if (callableMemberDescriptor.getKind() == CallableMemberDescriptor.Kind.DELEGATION) {
1697 Set<? extends CallableMemberDescriptor> overriddenDescriptors = callableMemberDescriptor.getOverriddenDescriptors();
1698 for (CallableMemberDescriptor overriddenDescriptor : overriddenDescriptors) {
1699 if (overriddenDescriptor.getContainingDeclaration() == toClass) {
1700 if (declaration instanceof PropertyDescriptor) {
1701 propertyCodegen
1702 .genDelegate((PropertyDescriptor) declaration, (PropertyDescriptor) overriddenDescriptor, field);
1703 }
1704 else if (declaration instanceof FunctionDescriptor) {
1705 functionCodegen
1706 .genDelegate((FunctionDescriptor) declaration, (FunctionDescriptor) overriddenDescriptor, field);
1707 }
1708 }
1709 }
1710 }
1711 }
1712 }
1713 }
1714
1715
1716 /**
1717 * Return pairs of descriptors. First is member of this that should be implemented by delegating to trait,
1718 * second is member of trait that contain implementation.
1719 */
1720 private List<Pair<CallableMemberDescriptor, CallableMemberDescriptor>> getTraitImplementations(@NotNull ClassDescriptor classDescriptor) {
1721 List<Pair<CallableMemberDescriptor, CallableMemberDescriptor>> r = Lists.newArrayList();
1722
1723 for (DeclarationDescriptor decl : classDescriptor.getDefaultType().getMemberScope().getAllDescriptors()) {
1724 if (!(decl instanceof CallableMemberDescriptor)) {
1725 continue;
1726 }
1727
1728 CallableMemberDescriptor callableMemberDescriptor = (CallableMemberDescriptor) decl;
1729 if (callableMemberDescriptor.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
1730 continue;
1731 }
1732
1733 Collection<CallableMemberDescriptor> overriddenDeclarations =
1734 OverridingUtil.getOverriddenDeclarations(callableMemberDescriptor);
1735
1736 Collection<CallableMemberDescriptor> filteredOverriddenDeclarations =
1737 OverridingUtil.filterOverrides(Sets.newLinkedHashSet(overriddenDeclarations));
1738
1739 int count = 0;
1740 CallableMemberDescriptor candidate = null;
1741
1742 for (CallableMemberDescriptor overriddenDeclaration : filteredOverriddenDeclarations) {
1743 if (isKindOf(overriddenDeclaration.getContainingDeclaration(), ClassKind.TRAIT) &&
1744 overriddenDeclaration.getModality() != Modality.ABSTRACT) {
1745 candidate = overriddenDeclaration;
1746 count++;
1747 }
1748 }
1749 if (candidate == null) {
1750 continue;
1751 }
1752
1753 assert count == 1 : "Ambiguous overridden declaration: " + callableMemberDescriptor.getName();
1754
1755
1756 Collection<JetType> superTypesOfSuperClass =
1757 superClassType != null ? TypeUtils.getAllSupertypes(superClassType) : Collections.<JetType>emptySet();
1758 ReceiverParameterDescriptor expectedThisObject = candidate.getExpectedThisObject();
1759 assert expectedThisObject != null;
1760 JetType candidateType = expectedThisObject.getType();
1761 boolean implementedInSuperClass = superTypesOfSuperClass.contains(candidateType);
1762
1763 if (!implementedInSuperClass) {
1764 r.add(Pair.create(callableMemberDescriptor, candidate));
1765 }
1766 }
1767 return r;
1768 }
1769
1770 public void addClassObjectPropertyToCopy(PropertyDescriptor descriptor, Object defaultValue) {
1771 if (classObjectPropertiesToCopy == null) {
1772 classObjectPropertiesToCopy = new ArrayList<PropertyAndDefaultValue>();
1773 }
1774 classObjectPropertiesToCopy.add(new PropertyAndDefaultValue(descriptor, defaultValue));
1775 }
1776
1777 static class PropertyAndDefaultValue {
1778
1779 PropertyAndDefaultValue(PropertyDescriptor propertyDescriptor, Object defaultValue) {
1780 this.propertyDescriptor = propertyDescriptor;
1781 this.defaultValue = defaultValue;
1782 }
1783
1784 private PropertyDescriptor propertyDescriptor;
1785
1786 private Object defaultValue;
1787
1788
1789 }
1790 }