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