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