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.signature.kotlin.JetMethodAnnotationWriter;
041    import org.jetbrains.jet.codegen.state.GenerationState;
042    import org.jetbrains.jet.codegen.state.JetTypeMapper;
043    import org.jetbrains.jet.codegen.state.JetTypeMapperMode;
044    import org.jetbrains.jet.lang.descriptors.*;
045    import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
046    import org.jetbrains.jet.lang.psi.*;
047    import org.jetbrains.jet.lang.resolve.BindingContext;
048    import org.jetbrains.jet.lang.resolve.BindingContextUtils;
049    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
050    import org.jetbrains.jet.lang.resolve.OverridingUtil;
051    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
052    import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
053    import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
054    import org.jetbrains.jet.lang.resolve.java.JvmAbi;
055    import org.jetbrains.jet.lang.resolve.java.JvmClassName;
056    import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
057    import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils;
058    import org.jetbrains.jet.lang.resolve.name.Name;
059    import org.jetbrains.jet.lang.types.JetType;
060    import org.jetbrains.jet.lang.types.TypeUtils;
061    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
062    import org.jetbrains.jet.lexer.JetTokens;
063    
064    import java.util.*;
065    
066    import static org.jetbrains.asm4.Opcodes.*;
067    import static org.jetbrains.jet.codegen.AsmUtil.*;
068    import static org.jetbrains.jet.codegen.CodegenUtil.*;
069    import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
070    import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration;
071    import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration;
072    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
073    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isKindOf;
074    import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE;
075    import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
076    
077    public class ImplementationBodyCodegen extends ClassBodyCodegen {
078        private static final String VALUES = "$VALUES";
079        private JetDelegationSpecifier superCall;
080        private Type superClassAsmType;
081        @Nullable // null means java/lang/Object
082        private JetType superClassType;
083        private final Type classAsmType;
084    
085        private final FunctionCodegen functionCodegen;
086        private final PropertyCodegen propertyCodegen;
087    
088        private List<PropertyAndDefaultValue> classObjectPropertiesToCopy;
089    
090        public ImplementationBodyCodegen(
091                @NotNull JetClassOrObject aClass,
092                @NotNull  ClassContext context,
093                @NotNull  ClassBuilder v,
094                @NotNull  GenerationState state,
095                @Nullable MemberCodegen parentCodegen
096        ) {
097            super(aClass, context, v, state, parentCodegen);
098            this.classAsmType = typeMapper.mapType(descriptor.getDefaultType(), JetTypeMapperMode.IMPL);
099            this.functionCodegen = new FunctionCodegen(context, v, state);
100            this.propertyCodegen = new PropertyCodegen(context, v, this.functionCodegen, this);
101        }
102    
103        @Override
104        protected void generateDeclaration() {
105            getSuperClass();
106    
107            JvmClassSignature signature = signature();
108    
109            boolean isAbstract = false;
110            boolean isInterface = false;
111            boolean isFinal = false;
112            boolean isStatic;
113            boolean isAnnotation = false;
114            boolean isEnum = false;
115    
116            if (myClass instanceof JetClass) {
117                JetClass jetClass = (JetClass) myClass;
118                if (jetClass.hasModifier(JetTokens.ABSTRACT_KEYWORD)) {
119                    isAbstract = true;
120                }
121                if (jetClass.isTrait()) {
122                    isAbstract = true;
123                    isInterface = true;
124                }
125                else if (jetClass.isAnnotation()) {
126                    isAbstract = true;
127                    isInterface = true;
128                    isAnnotation = true;
129                    signature.getInterfaces().add("java/lang/annotation/Annotation");
130                }
131                else if (jetClass.isEnum()) {
132                    isAbstract = hasAbstractMembers(descriptor);
133                    isEnum = true;
134                }
135    
136                if (descriptor.getKind() == ClassKind.OBJECT || descriptor.getKind() == ClassKind.CLASS_OBJECT) {
137                    isFinal = true;
138                }
139    
140                if (!jetClass.hasModifier(JetTokens.OPEN_KEYWORD) && !isAbstract) {
141                    isFinal = true;
142                }
143                isStatic = !jetClass.isInner();
144            }
145            else {
146                isStatic = myClass.getParent() instanceof JetClassObject;
147                isFinal = true;
148            }
149    
150            int access = 0;
151    
152            if (state.getClassBuilderMode() == ClassBuilderMode.SIGNATURES && !DescriptorUtils.isTopLevelDeclaration(descriptor)) {
153                // ClassBuilderMode.SIGNATURES means we are generating light classes & looking at a nested or inner class
154                // Light class generation is implemented so that Cls-classes only read bare code of classes,
155                // without knowing whether these classes are inner or not (see ClassStubBuilder.EMPTY_STRATEGY)
156                // Thus we must write full accessibility flags on inner classes in this mode
157                access |= getVisibilityAccessFlag(descriptor);
158                // Same for STATIC
159                if (isStatic) {
160                    access |= ACC_STATIC;
161                }
162            }
163            else {
164                access |= getVisibilityAccessFlagForClass(descriptor);
165            }
166            if (isAbstract) {
167                access |= ACC_ABSTRACT;
168            }
169            if (isInterface) {
170                access |= ACC_INTERFACE; // ACC_SUPER
171            }
172            else {
173                access |= ACC_SUPER;
174            }
175            if (isFinal) {
176                access |= ACC_FINAL;
177            }
178            if (isAnnotation) {
179                access |= ACC_ANNOTATION;
180            }
181            if (KotlinBuiltIns.getInstance().isDeprecated(descriptor)) {
182                access |= ACC_DEPRECATED;
183            }
184            if (isEnum) {
185                for (JetDeclaration declaration : myClass.getDeclarations()) {
186                    if (declaration instanceof JetEnumEntry) {
187                        if (enumEntryNeedSubclass(state.getBindingContext(), (JetEnumEntry) declaration)) {
188                            access &= ~ACC_FINAL;
189                        }
190                    }
191                }
192                access |= ACC_ENUM;
193            }
194            List<String> interfaces = signature.getInterfaces();
195            v.defineClass(myClass, V1_6,
196                          access,
197                          signature.getName(),
198                          signature.getJavaGenericSignature(),
199                          signature.getSuperclassName(),
200                          ArrayUtil.toStringArray(interfaces)
201            );
202            v.visitSource(myClass.getContainingFile().getName(), null);
203    
204            writeEnclosingMethod();
205    
206            writeOuterClasses();
207    
208            writeInnerClasses();
209    
210            AnnotationCodegen.forClass(v.getVisitor(), typeMapper).genAnnotations(descriptor);
211    
212            writeClassSignatureIfNeeded(signature);
213        }
214    
215        private void writeEnclosingMethod() {
216            //JVMS7: A class must have an EnclosingMethod attribute if and only if it is a local class or an anonymous class.
217            DeclarationDescriptor parentDescriptor = descriptor.getContainingDeclaration();
218    
219            boolean isObjectLiteral = DescriptorUtils.isAnonymous(descriptor);
220    
221            boolean isLocalOrAnonymousClass = isObjectLiteral ||
222                                              !(parentDescriptor instanceof NamespaceDescriptor || parentDescriptor instanceof ClassDescriptor);
223            if (isLocalOrAnonymousClass) {
224                String outerClassName = getOuterClassName(descriptor, typeMapper);
225                FunctionDescriptor function = DescriptorUtils.getParentOfType(descriptor, FunctionDescriptor.class);
226    
227                if (function != null) {
228                    Method method = typeMapper.mapSignature(function).getAsmMethod();
229                    v.visitOuterClass(outerClassName, method.getName(), method.getDescriptor());
230                }
231                else {
232                    assert isObjectLiteral
233                            : "Function descriptor could be null only for object literal in package namespace: " + descriptor.getName();
234                    v.visitOuterClass(outerClassName, null, null);
235                }
236            }
237        }
238    
239        @NotNull
240        private static String getOuterClassName(
241                @NotNull ClassDescriptor classDescriptor,
242                @NotNull JetTypeMapper typeMapper
243        ) {
244            ClassDescriptor container = DescriptorUtils.getParentOfType(classDescriptor, ClassDescriptor.class);
245            if (container != null) {
246                return typeMapper.mapType(container.getDefaultType(), JetTypeMapperMode.IMPL).getInternalName();
247            }
248            else {
249                JetFile containingFile = BindingContextUtils.getContainingFile(typeMapper.getBindingContext(), classDescriptor);
250                assert containingFile != null : "Containing file should be present for " + classDescriptor;
251                return NamespaceCodegen.getNamespacePartInternalName(containingFile);
252            }
253        }
254    
255        private void writeInnerClasses() {
256            Collection<ClassDescriptor> result = bindingContext.get(INNER_CLASSES, descriptor);
257            if (result != null) {
258                for (ClassDescriptor innerClass : result) {
259                    writeInnerClass(innerClass);
260                }
261            }
262        }
263    
264        private void writeOuterClasses() {
265            // JVMS7 (4.7.6): a nested class or interface member will have InnerClasses information
266            // for each enclosing class and for each immediate member
267            DeclarationDescriptor inner = descriptor;
268            while (true) {
269                if (inner == null || isTopLevelDeclaration(inner)) {
270                    break;
271                }
272                if (inner instanceof ClassDescriptor && !isEnumClassObject(inner)) {
273                    writeInnerClass((ClassDescriptor) inner);
274                }
275                inner = inner.getContainingDeclaration();
276            }
277        }
278    
279        private void writeInnerClass(@NotNull ClassDescriptor innerClass) {
280            // TODO: proper access
281            int innerClassAccess = getVisibilityAccessFlag(innerClass);
282            if (innerClass.getModality() == Modality.FINAL) {
283                innerClassAccess |= ACC_FINAL;
284            }
285            else if (innerClass.getModality() == Modality.ABSTRACT) {
286                innerClassAccess |= ACC_ABSTRACT;
287            }
288    
289            if (innerClass.getKind() == ClassKind.TRAIT) {
290                innerClassAccess |= ACC_INTERFACE;
291            }
292            else if (innerClass.getKind() == ClassKind.ENUM_CLASS) {
293                innerClassAccess |= ACC_ENUM;
294            }
295    
296            if (!innerClass.isInner()) {
297                innerClassAccess |= ACC_STATIC;
298            }
299    
300            // TODO: cache internal names
301            DeclarationDescriptor containing = innerClass.getContainingDeclaration();
302            String outerClassInternalName = containing instanceof ClassDescriptor ? getInternalNameForImpl((ClassDescriptor) containing) : null;
303    
304            String innerClassInternalName;
305            String innerName;
306    
307            if (isClassObject(innerClass)) {
308                innerName = JvmAbi.CLASS_OBJECT_CLASS_NAME;
309                innerClassInternalName = outerClassInternalName + JvmAbi.CLASS_OBJECT_SUFFIX;
310            }
311            else {
312                innerName = innerClass.getName().isSpecial() ? null : innerClass.getName().asString();
313                innerClassInternalName = getInternalNameForImpl(innerClass);
314            }
315    
316            v.visitInnerClass(innerClassInternalName, outerClassInternalName, innerName, innerClassAccess);
317        }
318    
319        @NotNull
320        private String getInternalNameForImpl(@NotNull ClassDescriptor descriptor) {
321            return typeMapper.mapType(descriptor.getDefaultType(), JetTypeMapperMode.IMPL).getInternalName();
322        }
323    
324        private void writeClassSignatureIfNeeded(JvmClassSignature signature) {
325            AnnotationVisitor annotationVisitor = v.newAnnotation(JvmStdlibNames.JET_CLASS.getDescriptor(), true);
326            annotationVisitor.visit(JvmStdlibNames.JET_CLASS_SIGNATURE, signature.getKotlinGenericSignature());
327            int flags = getFlagsForVisibility(descriptor.getVisibility()) | getFlagsForClassKind(descriptor);
328            if (JvmStdlibNames.FLAGS_DEFAULT_VALUE != flags) {
329                annotationVisitor.visit(JvmStdlibNames.JET_FLAGS_FIELD, flags);
330            }
331            annotationVisitor.visit(JvmStdlibNames.ABI_VERSION_NAME, JvmAbi.VERSION);
332            annotationVisitor.visitEnd();
333    
334            if (descriptor.getKind() == ClassKind.CLASS_OBJECT) {
335                AnnotationVisitor classObjectVisitor = v.newAnnotation(JvmStdlibNames.JET_CLASS_OBJECT.getDescriptor(), true);
336                classObjectVisitor.visitEnd();
337            }
338        }
339    
340        private JvmClassSignature signature() {
341            List<String> superInterfaces;
342    
343            LinkedHashSet<String> superInterfacesLinkedHashSet = new LinkedHashSet<String>();
344    
345            // TODO: generics signature is not always needed
346            BothSignatureWriter signatureVisitor = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS, true);
347    
348    
349            {   // type parameters
350                List<TypeParameterDescriptor> typeParameters = descriptor.getTypeConstructor().getParameters();
351                typeMapper.writeFormalTypeParameters(typeParameters, signatureVisitor);
352            }
353    
354            signatureVisitor.writeSupersStart();
355    
356            {   // superclass
357                signatureVisitor.writeSuperclass();
358                if (superClassType == null) {
359                    signatureVisitor.writeClassBegin(superClassAsmType.getInternalName(), false, false);
360                    signatureVisitor.writeClassEnd();
361                }
362                else {
363                    typeMapper.mapType(superClassType, signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER);
364                }
365                signatureVisitor.writeSuperclassEnd();
366            }
367    
368    
369            {   // superinterfaces
370                superInterfacesLinkedHashSet.add(JvmStdlibNames.JET_OBJECT.getInternalName());
371    
372                for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) {
373                    JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference());
374                    assert superType != null;
375                    ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
376                    if (isInterface(superClassDescriptor)) {
377                        signatureVisitor.writeInterface();
378                        Type jvmName = typeMapper.mapType(superType, signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER);
379                        signatureVisitor.writeInterfaceEnd();
380                        superInterfacesLinkedHashSet.add(jvmName.getInternalName());
381                    }
382                }
383    
384                superInterfaces = new ArrayList<String>(superInterfacesLinkedHashSet);
385            }
386    
387            signatureVisitor.writeSupersEnd();
388    
389            return new JvmClassSignature(jvmName(), superClassAsmType.getInternalName(), superInterfaces, signatureVisitor.makeJavaGenericSignature(),
390                                         signatureVisitor.makeKotlinClassSignature());
391        }
392    
393        private String jvmName() {
394            if (kind != OwnerKind.IMPLEMENTATION) {
395                throw new IllegalStateException("must not call this method with kind " + kind);
396            }
397            return classAsmType.getInternalName();
398        }
399    
400        protected void getSuperClass() {
401            superClassAsmType = AsmTypeConstants.OBJECT_TYPE;
402            superClassType = null;
403    
404            List<JetDelegationSpecifier> delegationSpecifiers = myClass.getDelegationSpecifiers();
405    
406            if (myClass instanceof JetClass && ((JetClass) myClass).isTrait()) {
407                return;
408            }
409    
410            if (kind != OwnerKind.IMPLEMENTATION) {
411                throw new IllegalStateException("must be impl to reach this code: " + kind);
412            }
413    
414            for (JetDelegationSpecifier specifier : delegationSpecifiers) {
415                if (specifier instanceof JetDelegatorToSuperClass || specifier instanceof JetDelegatorToSuperCall) {
416                    JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference());
417                    assert superType != null;
418                    ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
419                    assert superClassDescriptor != null;
420                    if (!isInterface(superClassDescriptor)) {
421                        superClassType = superType;
422                        superClassAsmType = typeMapper.mapType(superClassDescriptor.getDefaultType(), JetTypeMapperMode.IMPL);
423                        superCall = specifier;
424                    }
425                }
426            }
427    
428            if (superClassType == null) {
429                if (descriptor.getKind() == ClassKind.ENUM_CLASS) {
430                    superClassType = KotlinBuiltIns.getInstance().getEnumType(descriptor.getDefaultType());
431                    superClassAsmType = typeMapper.mapType(superClassType);
432                }
433                if (descriptor.getKind() == ClassKind.ENUM_ENTRY) {
434                    superClassType = descriptor.getTypeConstructor().getSupertypes().iterator().next();
435                    superClassAsmType = typeMapper.mapType(superClassType);
436                }
437            }
438        }
439    
440        @Override
441        protected void generateSyntheticParts() {
442            generateFieldForSingleton();
443    
444            generateClassObjectBackingFieldCopies();
445    
446            try {
447                generatePrimaryConstructor();
448            }
449            catch (CompilationException e) {
450                throw e;
451            }
452            catch (ProcessCanceledException e) {
453                throw e;
454            }
455            catch (RuntimeException e) {
456                throw new RuntimeException("Error generating primary constructor of class " + myClass.getName() + " with kind " + kind, e);
457            }
458    
459            generateTraitMethods();
460    
461            generateSyntheticAccessors();
462    
463            generateEnumMethodsAndConstInitializers();
464    
465            generateFunctionsForDataClasses();
466    
467            genClosureFields(context.closure, v, state.getTypeMapper());
468        }
469    
470        private List<PropertyDescriptor> getDataProperties() {
471            ArrayList<PropertyDescriptor> result = Lists.newArrayList();
472            for (JetParameter parameter : getPrimaryConstructorParameters()) {
473                if (parameter.getValOrVarNode() == null) continue;
474    
475                PropertyDescriptor propertyDescriptor = DescriptorUtils.getPropertyDescriptor(parameter, bindingContext);
476    
477                result.add(propertyDescriptor);
478            }
479            return result;
480        }
481    
482        private void generateFunctionsForDataClasses() {
483            if (!KotlinBuiltIns.getInstance().isData(descriptor)) return;
484    
485            generateComponentFunctionsForDataClasses();
486            generateCopyFunctionForDataClasses();
487    
488            List<PropertyDescriptor> properties = getDataProperties();
489            if (!properties.isEmpty()) {
490                generateDataClassToStringIfNeeded(properties);
491                generateDataClassHashCodeIfNeeded(properties);
492                generateDataClassEqualsIfNeeded(properties);
493            }
494        }
495    
496        private void generateCopyFunctionForDataClasses() {
497            FunctionDescriptor copyFunction = bindingContext.get(BindingContext.DATA_CLASS_COPY_FUNCTION, descriptor);
498            if (copyFunction != null) {
499                generateCopyFunction(copyFunction);
500            }
501        }
502    
503        private void generateDataClassToStringIfNeeded(List<PropertyDescriptor> properties) {
504            ClassDescriptor stringClass = KotlinBuiltIns.getInstance().getString();
505            if (getDeclaredFunctionByRawSignature(descriptor, Name.identifier("toString"), stringClass) == null) {
506                generateDataClassToStringMethod(properties);
507            }
508        }
509    
510        private void generateDataClassHashCodeIfNeeded(List<PropertyDescriptor> properties) {
511            ClassDescriptor intClass = KotlinBuiltIns.getInstance().getInt();
512            if (getDeclaredFunctionByRawSignature(descriptor, Name.identifier("hashCode"), intClass) == null) {
513                generateDataClassHashCodeMethod(properties);
514            }
515        }
516    
517        private void generateDataClassEqualsIfNeeded(List<PropertyDescriptor> properties) {
518            ClassDescriptor booleanClass = KotlinBuiltIns.getInstance().getBoolean();
519            ClassDescriptor anyClass = KotlinBuiltIns.getInstance().getAny();
520            FunctionDescriptor equalsFunction = getDeclaredFunctionByRawSignature(descriptor, Name.identifier("equals"), booleanClass, anyClass);
521            if (equalsFunction == null) {
522                generateDataClassEqualsMethod(properties);
523            }
524        }
525    
526        private void generateDataClassEqualsMethod(List<PropertyDescriptor> properties) {
527            MethodVisitor mv = v.getVisitor().visitMethod(ACC_PUBLIC, "equals", "(Ljava/lang/Object;)Z", null, null);
528            InstructionAdapter iv = new InstructionAdapter(mv);
529    
530            mv.visitCode();
531            Label eq = new Label();
532            Label ne = new Label();
533    
534            iv.load(0, OBJECT_TYPE);
535            iv.load(1, AsmTypeConstants.OBJECT_TYPE);
536            iv.ifacmpeq(eq);
537    
538            iv.load(1, AsmTypeConstants.OBJECT_TYPE);
539            iv.instanceOf(classAsmType);
540            iv.ifeq(ne);
541    
542            iv.load(1, AsmTypeConstants.OBJECT_TYPE);
543            iv.checkcast(classAsmType);
544            iv.store(2, AsmTypeConstants.OBJECT_TYPE);
545    
546            for (PropertyDescriptor propertyDescriptor : properties) {
547                Type asmType = typeMapper.mapType(propertyDescriptor.getType());
548    
549                genPropertyOnStack(iv, propertyDescriptor, 0);
550                genPropertyOnStack(iv, propertyDescriptor, 2);
551    
552                if (asmType.getSort() == Type.ARRAY) {
553                    Type elementType = correctElementType(asmType);
554                    if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
555                        iv.invokestatic("java/util/Arrays", "equals", "([Ljava/lang/Object;[Ljava/lang/Object;)Z");
556                    }
557                    else {
558                        iv.invokestatic("java/util/Arrays", "equals", "([" + elementType.getDescriptor() + "[" + elementType.getDescriptor() + ")Z");
559                    }
560                }
561                else {
562                    StackValue value = genEqualsForExpressionsOnStack(iv, JetTokens.EQEQ, asmType, asmType);
563                    value.put(Type.BOOLEAN_TYPE, iv);
564                }
565    
566                iv.ifeq(ne);
567            }
568    
569            iv.mark(eq);
570            iv.iconst(1);
571            iv.areturn(Type.INT_TYPE);
572    
573            iv.mark(ne);
574            iv.iconst(0);
575            iv.areturn(Type.INT_TYPE);
576    
577            FunctionCodegen.endVisit(mv, "equals", myClass);
578        }
579    
580        private void generateDataClassHashCodeMethod(List<PropertyDescriptor> properties) {
581            MethodVisitor mv = v.getVisitor().visitMethod(ACC_PUBLIC, "hashCode", "()I", null, null);
582            InstructionAdapter iv = new InstructionAdapter(mv);
583    
584            mv.visitCode();
585            boolean first = true;
586            for (PropertyDescriptor propertyDescriptor : properties) {
587                if (!first) {
588                    iv.iconst(31);
589                    iv.mul(Type.INT_TYPE);
590                }
591    
592                genPropertyOnStack(iv, propertyDescriptor, 0);
593    
594                Label ifNull = null;
595                Type asmType = typeMapper.mapType(propertyDescriptor.getType());
596                if (!isPrimitive(asmType)) {
597                    ifNull = new Label();
598                    iv.dup();
599                    iv.ifnull(ifNull);
600                }
601    
602                genHashCode(mv, iv, asmType);
603    
604                if (ifNull != null) {
605                    Label end = new Label();
606                    iv.goTo(end);
607                    iv.mark(ifNull);
608                    iv.pop();
609                    iv.iconst(0);
610                    iv.mark(end);
611                }
612    
613                if (first) {
614                    first = false;
615                }
616                else {
617                    iv.add(Type.INT_TYPE);
618                }
619            }
620    
621            mv.visitInsn(IRETURN);
622    
623            FunctionCodegen.endVisit(mv, "hashCode", myClass);
624        }
625    
626        private void generateDataClassToStringMethod(List<PropertyDescriptor> properties) {
627            MethodVisitor mv = v.getVisitor().visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null);
628            InstructionAdapter iv = new InstructionAdapter(mv);
629    
630            mv.visitCode();
631            genStringBuilderConstructor(iv);
632    
633            boolean first = true;
634            for (PropertyDescriptor propertyDescriptor : properties) {
635                if (first) {
636                    iv.aconst(descriptor.getName() + "(" + propertyDescriptor.getName().asString()+"=");
637                    first = false;
638                }
639                else {
640                    iv.aconst(", " + propertyDescriptor.getName().asString()+"=");
641                }
642                genInvokeAppendMethod(iv, JAVA_STRING_TYPE);
643    
644                Type type = genPropertyOnStack(iv, propertyDescriptor, 0);
645    
646                if (type.getSort() == Type.ARRAY) {
647                    Type elementType = correctElementType(type);
648                    if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
649                        iv.invokestatic("java/util/Arrays", "toString", "([Ljava/lang/Object;)Ljava/lang/String;");
650                        type = JAVA_STRING_TYPE;
651                    }
652                    else {
653                        if (elementType.getSort() != Type.CHAR) {
654                            iv.invokestatic("java/util/Arrays", "toString", "(" + type.getDescriptor() + ")Ljava/lang/String;");
655                            type = JAVA_STRING_TYPE;
656                        }
657                    }
658                }
659                genInvokeAppendMethod(iv, type);
660            }
661    
662            iv.aconst(")");
663            genInvokeAppendMethod(iv, JAVA_STRING_TYPE);
664    
665            iv.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
666            iv.areturn(JAVA_STRING_TYPE);
667    
668            FunctionCodegen.endVisit(mv, "toString", myClass);
669        }
670    
671        private Type genPropertyOnStack(InstructionAdapter iv, PropertyDescriptor propertyDescriptor, int index) {
672            iv.load(index, classAsmType);
673            Method
674                    method = typeMapper.mapGetterSignature(propertyDescriptor, OwnerKind.IMPLEMENTATION).getAsmMethod();
675    
676            iv.invokevirtual(classAsmType.getInternalName(), method.getName(), method.getDescriptor());
677            return method.getReturnType();
678        }
679    
680        private void generateComponentFunctionsForDataClasses() {
681            if (!myClass.hasPrimaryConstructor() || !KotlinBuiltIns.getInstance().isData(descriptor)) return;
682    
683            ConstructorDescriptor constructor = descriptor.getConstructors().iterator().next();
684    
685            for (ValueParameterDescriptor parameter : constructor.getValueParameters()) {
686                FunctionDescriptor function = bindingContext.get(BindingContext.DATA_CLASS_COMPONENT_FUNCTION, parameter);
687                if (function != null) {
688                    generateComponentFunction(function, parameter);
689                }
690            }
691        }
692    
693        private void generateComponentFunction(@NotNull FunctionDescriptor function, @NotNull final ValueParameterDescriptor parameter) {
694            JetType returnType = function.getReturnType();
695            assert returnType != null : "Return type of component function should not be null: " + function;
696            final Type componentType = typeMapper.mapReturnType(returnType);
697    
698            JvmMethodSignature signature = typeMapper.mapSignature(function);
699    
700            FunctionCodegen fc = new FunctionCodegen(context, v, state);
701            fc.generateMethod(myClass, signature, true, function, new FunctionGenerationStrategy() {
702                @Override
703                public void generateBody(
704                        @NotNull MethodVisitor mv,
705                        @NotNull JvmMethodSignature signature,
706                        @NotNull MethodContext context
707                ) {
708                    InstructionAdapter iv = new InstructionAdapter(mv);
709                    if (!componentType.equals(Type.VOID_TYPE)) {
710                        iv.load(0, classAsmType);
711                        String desc = "()" + componentType.getDescriptor();
712                        iv.invokevirtual(classAsmType.getInternalName(), PropertyCodegen.getterName(parameter.getName()), desc);
713                    }
714                    iv.areturn(componentType);
715                }
716            });
717        }
718    
719        private void generateCopyFunction(@NotNull final FunctionDescriptor function) {
720            JvmMethodSignature methodSignature = typeMapper.mapSignature(function);
721    
722            final Type thisDescriptorType = typeMapper.mapType(descriptor.getDefaultType());
723    
724            FunctionCodegen fc = new FunctionCodegen(context, v, state);
725            fc.generateMethod(myClass, methodSignature, true, function, new FunctionGenerationStrategy() {
726                @Override
727                public void generateBody(
728                        @NotNull MethodVisitor mv,
729                        @NotNull JvmMethodSignature signature,
730                        @NotNull MethodContext context
731                ) {
732                    InstructionAdapter iv = new InstructionAdapter(mv);
733    
734                    iv.anew(thisDescriptorType);
735                    iv.dup();
736    
737                    ConstructorDescriptor constructor = DescriptorUtils.getConstructorOfDataClass(descriptor);
738                    assert function.getValueParameters().size() == constructor.getValueParameters().size() :
739                            "Number of parameters of copy function and constructor are different. " +
740                            "Copy: " + function.getValueParameters().size() + ", " +
741                            "constructor: " + constructor.getValueParameters().size();
742    
743                    MutableClosure closure = ImplementationBodyCodegen.this.context.closure;
744                    if (closure != null && closure.getCaptureThis() != null) {
745                        Type type = typeMapper.mapType(enclosingClassDescriptor(bindingContext, descriptor));
746                        iv.load(0, classAsmType);
747                        iv.getfield(JvmClassName.byType(classAsmType).getInternalName(), CAPTURED_THIS_FIELD, type.getDescriptor());
748                    }
749    
750                    int parameterIndex = 1; // localVariable 0 = this
751                    for (ValueParameterDescriptor parameterDescriptor : function.getValueParameters()) {
752                        Type type = typeMapper.mapType(parameterDescriptor.getType());
753                        iv.load(parameterIndex, type);
754                        parameterIndex += type.getSize();
755                    }
756    
757                    String constructorJvmDescriptor = typeMapper.mapToCallableMethod(constructor).getSignature().getAsmMethod().getDescriptor();
758                    iv.invokespecial(thisDescriptorType.getInternalName(), "<init>", constructorJvmDescriptor);
759    
760                    iv.areturn(thisDescriptorType);
761                }
762            });
763    
764            MethodContext functionContext = context.intoFunction(function);
765            FunctionCodegen.generateDefaultIfNeeded(functionContext, state, v, methodSignature, function, OwnerKind.IMPLEMENTATION,
766                        new DefaultParameterValueLoader() {
767                            @Override
768                            public void putValueOnStack(
769                                    ValueParameterDescriptor descriptor,
770                                    ExpressionCodegen codegen
771                            ) {
772                                assert (KotlinBuiltIns.getInstance().isData((ClassDescriptor) function.getContainingDeclaration()))
773                                        : "Trying to create function with default arguments for function that isn't presented in code for class without data annotation";
774                                PropertyDescriptor propertyDescriptor = codegen.getBindingContext().get(
775                                        BindingContext.VALUE_PARAMETER_AS_PROPERTY, descriptor);
776                                assert propertyDescriptor != null
777                                        : "Trying to generate default value for parameter of copy function that doesn't correspond to any property";
778                                codegen.v.load(0, thisDescriptorType);
779                                Type propertyType = codegen.typeMapper.mapType(propertyDescriptor.getType());
780                                codegen.intermediateValueForProperty(propertyDescriptor, false, null).put(propertyType, codegen.v);
781                            }
782                        });
783    }
784    
785        private void generateEnumMethodsAndConstInitializers() {
786            if (!myEnumConstants.isEmpty()) {
787                generateEnumMethods();
788    
789                if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
790                    initializeEnumConstants(createOrGetClInitCodegen());
791                }
792            }
793        }
794    
795        private void generateEnumMethods() {
796            if (myEnumConstants.size() > 0) {
797                {
798                    Type type =
799                            typeMapper.mapType(KotlinBuiltIns.getInstance().getArrayType(descriptor.getDefaultType()),
800                                               JetTypeMapperMode.IMPL);
801    
802                    MethodVisitor mv =
803                            v.newMethod(myClass, ACC_PUBLIC | ACC_STATIC, "values", "()" + type.getDescriptor(), null, null);
804                    mv.visitCode();
805                    mv.visitFieldInsn(GETSTATIC, typeMapper.mapType(descriptor).getInternalName(),
806                                      VALUES,
807                                      type.getDescriptor());
808                    mv.visitMethodInsn(INVOKEVIRTUAL, type.getInternalName(), "clone", "()Ljava/lang/Object;");
809                    mv.visitTypeInsn(CHECKCAST, type.getInternalName());
810                    mv.visitInsn(ARETURN);
811                    FunctionCodegen.endVisit(mv, "values()", myClass);
812                }
813                {
814    
815                    MethodVisitor mv =
816                            v.newMethod(myClass, ACC_PUBLIC | ACC_STATIC, "valueOf", "(Ljava/lang/String;)" + classAsmType.getDescriptor(), null,
817                                        null);
818                    mv.visitCode();
819                    mv.visitLdcInsn(classAsmType);
820                    mv.visitVarInsn(ALOAD, 0);
821                    mv.visitMethodInsn(INVOKESTATIC, "java/lang/Enum", "valueOf", "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;");
822                    mv.visitTypeInsn(CHECKCAST, classAsmType.getInternalName());
823                    mv.visitInsn(ARETURN);
824                    FunctionCodegen.endVisit(mv, "values()", myClass);
825                }
826            }
827        }
828    
829        protected void generateSyntheticAccessors() {
830            Map<DeclarationDescriptor, DeclarationDescriptor> accessors = context.getAccessors();
831            for (Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry : accessors.entrySet()) {
832                generateSyntheticAccessor(entry);
833            }
834        }
835    
836        private void generateSyntheticAccessor(Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry) {
837            if (entry.getValue() instanceof FunctionDescriptor) {
838                FunctionDescriptor bridge = (FunctionDescriptor) entry.getValue();
839                final FunctionDescriptor original = (FunctionDescriptor) entry.getKey();
840                 functionCodegen.generateMethod(null, typeMapper.mapSignature(bridge), false, bridge,
841                       new FunctionGenerationStrategy.CodegenBased<FunctionDescriptor>(state, bridge) {
842                           @Override
843                           public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
844                               generateMethodCallTo(original, codegen.v);
845    
846                               codegen.v.areturn(signature.getAsmMethod().getReturnType());
847                           }
848                       });
849            }
850            else if (entry.getValue() instanceof PropertyDescriptor) {
851                final PropertyDescriptor bridge = (PropertyDescriptor) entry.getValue();
852                final PropertyDescriptor original = (PropertyDescriptor) entry.getKey();
853    
854    
855                PropertyGetterDescriptor getter = bridge.getGetter();
856                assert getter != null;
857                functionCodegen.generateMethod(null, typeMapper.mapGetterSignature(bridge, OwnerKind.IMPLEMENTATION), false, getter,
858                                               new FunctionGenerationStrategy.CodegenBased<PropertyGetterDescriptor>(state, getter) {
859                    @Override
860                    public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
861                        InstructionAdapter iv = codegen.v;
862                        boolean forceField = AsmUtil.isPropertyWithBackingFieldInOuterClass(original) && !isClassObject(bridge.getContainingDeclaration());
863                        StackValue property = codegen.intermediateValueForProperty(original, forceField, null, MethodKind.SYNTHETIC_ACCESSOR);
864                        if (!forceField) {
865                            iv.load(0, OBJECT_TYPE);
866                        }
867                        property.put(property.type, iv);
868                        iv.areturn(signature.getAsmMethod().getReturnType());
869                    }
870                });
871    
872    
873                if (bridge.isVar()) {
874                    PropertySetterDescriptor setter = bridge.getSetter();
875                    assert setter != null;
876    
877                    functionCodegen.generateMethod(null, typeMapper.mapSetterSignature(bridge, OwnerKind.IMPLEMENTATION), false, setter,
878                                                   new FunctionGenerationStrategy.CodegenBased<PropertySetterDescriptor>(state, setter) {
879                        @Override
880                        public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
881                            boolean forceField = AsmUtil.isPropertyWithBackingFieldInOuterClass(original) && !isClassObject(bridge.getContainingDeclaration());
882                            StackValue property = codegen.intermediateValueForProperty(original, forceField, null, MethodKind.SYNTHETIC_ACCESSOR);
883                            InstructionAdapter iv = codegen.v;
884    
885                            Type[] argTypes = signature.getAsmMethod().getArgumentTypes();
886                            for (int i = 0, reg = 0; i < argTypes.length; i++) {
887                                Type argType = argTypes[i];
888                                iv.load(reg, argType);
889                                //noinspection AssignmentToForLoopParameter
890                                reg += argType.getSize();
891                            }
892                            property.store(property.type, iv);
893    
894                            iv.areturn(signature.getAsmMethod().getReturnType());
895                        }
896                    });
897                }
898            }
899            else {
900                throw new UnsupportedOperationException();
901            }
902        }
903    
904        private void generateMethodCallTo(FunctionDescriptor functionDescriptor, InstructionAdapter iv) {
905            boolean isConstructor = functionDescriptor instanceof ConstructorDescriptor;
906            boolean callFromAccessor = !JetTypeMapper.isAccessor(functionDescriptor);
907            CallableMethod callableMethod = isConstructor ?
908                                            typeMapper.mapToCallableMethod((ConstructorDescriptor) functionDescriptor) :
909                                            typeMapper.mapToCallableMethod(functionDescriptor, callFromAccessor,
910                                                                           isCallInsideSameClassAsDeclared(functionDescriptor, context),
911                                                                           isCallInsideSameModuleAsDeclared(functionDescriptor, context),
912                                                                           context.getContextKind());
913    
914            Method method = callableMethod.getSignature().getAsmMethod();
915            Type[] argTypes = method.getArgumentTypes();
916    
917            int reg = 1;
918            if (isConstructor) {
919                iv.anew(callableMethod.getOwner().getAsmType());
920                iv.dup();
921                reg = 0;
922            }
923            else if (callFromAccessor) {
924                iv.load(0, OBJECT_TYPE);
925            }
926    
927            for (int paramIndex = 0; paramIndex < argTypes.length; paramIndex++) {
928                Type argType = argTypes[paramIndex];
929                iv.load(reg, argType);
930                //noinspection AssignmentToForLoopParameter
931                reg += argType.getSize();
932            }
933            callableMethod.invokeWithoutAssertions(iv);
934        }
935    
936        private void generateFieldForSingleton() {
937            boolean hasClassObject = descriptor.getClassObjectDescriptor() != null;
938            boolean isEnumClass = DescriptorUtils.isEnumClass(descriptor);
939    
940            if (!(isNonLiteralObject(myClass) || 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, true, 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                writeAnnotationForDelegateToTraitImpl(fun, inheritedFun, mv);
1365    
1366                Type returnType = methodToGenerate.getReturnType();
1367    
1368                mv.visitCode();
1369                FrameMap frameMap = context.prepareFrame(typeMapper);
1370                ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, returnType, context.intoFunction(inheritedFun), state);
1371                codegen.generateThisOrOuter(descriptor, false);    // ??? wouldn't it be addClosureToConstructorParameters good idea to put it?
1372    
1373                Type[] argTypes = methodToGenerate.getArgumentTypes();
1374                Type[] originalArgTypes = methodInTrait.getArgumentTypes();
1375    
1376                InstructionAdapter iv = new InstructionAdapter(mv);
1377                iv.load(0, OBJECT_TYPE);
1378                for (int i = 0, reg = 1; i < argTypes.length; i++) {
1379                    StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
1380                    //noinspection AssignmentToForLoopParameter
1381                    reg += argTypes[i].getSize();
1382                }
1383    
1384                Type type = getTraitImplThisParameterType(containingClass, typeMapper);
1385                String functionDescriptor = methodInTrait.getDescriptor().replace("(", "(" + type.getDescriptor());
1386    
1387                Type tImplType = typeMapper.mapType(containingClass.getDefaultType(), JetTypeMapperMode.TRAIT_IMPL);
1388    
1389                iv.invokestatic(tImplType.getInternalName(), methodToGenerate.getName(), functionDescriptor);
1390                StackValue.onStack(methodInTrait.getReturnType()).put(returnType, iv);
1391                iv.areturn(returnType);
1392    
1393                FunctionCodegen.endVisit(iv, "trait method", callableDescriptorToDeclaration(bindingContext, fun));
1394            }
1395    
1396            FunctionCodegen.generateBridgeIfNeeded(context, state, v, methodToGenerate, fun);
1397        }
1398    
1399        private static class TraitImplDelegateInfo {
1400            private final Method methodToGenerate;
1401            private final Method methodInTrait;
1402    
1403            private TraitImplDelegateInfo(@NotNull Method methodToGenerate, @NotNull Method methodInTrait) {
1404                this.methodToGenerate = methodToGenerate;
1405                this.methodInTrait = methodInTrait;
1406            }
1407        }
1408    
1409        @NotNull
1410        private TraitImplDelegateInfo getTraitImplDelegateInfo(@NotNull FunctionDescriptor fun) {
1411            if (fun instanceof PropertyAccessorDescriptor) {
1412                PropertyDescriptor property = ((PropertyAccessorDescriptor) fun).getCorrespondingProperty();
1413                PropertyDescriptor original = property.getOriginal();
1414                if (fun instanceof PropertyGetterDescriptor) {
1415                    JvmPropertyAccessorSignature toGenerate = typeMapper.mapGetterSignature(property, OwnerKind.IMPLEMENTATION);
1416                    JvmPropertyAccessorSignature inTrait = typeMapper.mapGetterSignature(original, OwnerKind.IMPLEMENTATION);
1417                    return new TraitImplDelegateInfo(
1418                            toGenerate.getAsmMethod(), inTrait.getAsmMethod());
1419                }
1420                else if (fun instanceof PropertySetterDescriptor) {
1421                    JvmPropertyAccessorSignature toGenerate = typeMapper.mapSetterSignature(property, OwnerKind.IMPLEMENTATION);
1422                    JvmPropertyAccessorSignature inTrait = typeMapper.mapSetterSignature(original, OwnerKind.IMPLEMENTATION);
1423                    return new TraitImplDelegateInfo(
1424                            toGenerate.getAsmMethod(), inTrait.getAsmMethod());
1425                }
1426                else {
1427                    throw new IllegalStateException("Accessor is neither getter, nor setter, what is it? " + fun);
1428                }
1429            }
1430            else {
1431                Method function = typeMapper.mapSignature(fun).getAsmMethod();
1432                Method functionOriginal = typeMapper.mapSignature(fun.getOriginal()).getAsmMethod();
1433                return new TraitImplDelegateInfo(function, functionOriginal);
1434            }
1435        }
1436    
1437        private void writeAnnotationForDelegateToTraitImpl(
1438                @NotNull FunctionDescriptor fun,
1439                @NotNull FunctionDescriptor inheritedFun,
1440                @NotNull MethodVisitor mv
1441        ) {
1442            JvmMethodSignature jvmSignature = typeMapper.mapSignature(inheritedFun, true, OwnerKind.IMPLEMENTATION);
1443            JetMethodAnnotationWriter aw = JetMethodAnnotationWriter.visitAnnotation(mv);
1444            int kotlinFlags = getFlagsForVisibility(fun.getVisibility());
1445            if (fun instanceof PropertyAccessorDescriptor) {
1446                kotlinFlags |= JvmStdlibNames.FLAG_PROPERTY_BIT;
1447                aw.writeTypeParameters(jvmSignature.getKotlinTypeParameter());
1448                aw.writePropertyType(jvmSignature.getKotlinReturnType());
1449            }
1450            else {
1451                aw.writeTypeParameters(jvmSignature.getKotlinTypeParameter());
1452                aw.writeReturnType(jvmSignature.getKotlinReturnType());
1453            }
1454            kotlinFlags |= DescriptorKindUtils.kindToFlags(inheritedFun.getKind());
1455            aw.writeFlags(kotlinFlags);
1456            aw.visitEnd();
1457        }
1458    
1459        private void generateDelegatorToConstructorCall(
1460                InstructionAdapter iv, ExpressionCodegen codegen,
1461                ConstructorDescriptor constructorDescriptor
1462        ) {
1463            ClassDescriptor classDecl = constructorDescriptor.getContainingDeclaration();
1464    
1465            iv.load(0, OBJECT_TYPE);
1466    
1467            if (classDecl.getKind() == ClassKind.ENUM_CLASS || classDecl.getKind() == ClassKind.ENUM_ENTRY) {
1468                iv.load(1, OBJECT_TYPE);
1469                iv.load(2, Type.INT_TYPE);
1470            }
1471    
1472            CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor, context.closure);
1473    
1474            ResolvedCall<? extends CallableDescriptor> resolvedCall =
1475                    bindingContext.get(BindingContext.RESOLVED_CALL, ((JetCallElement) superCall).getCalleeExpression());
1476            assert resolvedCall != null;
1477            ConstructorDescriptor superConstructor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor();
1478    
1479            //noinspection SuspiciousMethodCalls
1480            CalculatedClosure closureForSuper = bindingContext.get(CLOSURE, superConstructor.getContainingDeclaration());
1481            CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor, closureForSuper);
1482    
1483            if (closureForSuper != null && closureForSuper.getCaptureThis() != null) {
1484                iv.load(((ConstructorFrameMap)codegen.myFrameMap).getOuterThisIndex(), OBJECT_TYPE);
1485            }
1486    
1487            if (myClass instanceof JetObjectDeclaration &&
1488                superCall instanceof JetDelegatorToSuperCall &&
1489                ((JetObjectDeclaration) myClass).isObjectLiteral()) {
1490                int nextVar = findFirstSuperArgument(method);
1491                for (Type t : superCallable.getSignature().getAsmMethod().getArgumentTypes()) {
1492                    iv.load(nextVar, t);
1493                    nextVar += t.getSize();
1494                }
1495                superCallable.invokeWithNotNullAssertion(codegen.v, state, resolvedCall);
1496            }
1497            else {
1498                codegen.invokeMethodWithArguments(superCallable, resolvedCall, null, StackValue.none());
1499            }
1500        }
1501    
1502        private static int findFirstSuperArgument(CallableMethod method) {
1503            List<JvmMethodParameterSignature> types = method.getSignature().getKotlinParameterTypes();
1504            int i = 0;
1505            for (JvmMethodParameterSignature type : types) {
1506                if (type.getKind() == JvmMethodParameterKind.SUPER_CALL_PARAM) {
1507                    return i + 1; // because of this
1508                }
1509                i += type.getAsmType().getSize();
1510            }
1511            return -1;
1512        }
1513    
1514        @Override
1515        protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration) {
1516            if (declaration instanceof JetEnumEntry) {
1517                String name = declaration.getName();
1518                String desc = "L" + classAsmType.getInternalName() + ";";
1519                v.newField(declaration, ACC_PUBLIC | ACC_ENUM | ACC_STATIC | ACC_FINAL, name, desc, null, null);
1520                myEnumConstants.add((JetEnumEntry) declaration);
1521            }
1522    
1523            super.generateDeclaration(propertyCodegen, declaration);
1524        }
1525    
1526        private final List<JetEnumEntry> myEnumConstants = new ArrayList<JetEnumEntry>();
1527    
1528        private void initializeEnumConstants(ExpressionCodegen codegen) {
1529            InstructionAdapter iv = codegen.v;
1530            int ordinal = -1;
1531            JetType myType = descriptor.getDefaultType();
1532            Type myAsmType = typeMapper.mapType(myType, JetTypeMapperMode.IMPL);
1533    
1534            assert myEnumConstants.size() > 0;
1535            JetType arrayType = KotlinBuiltIns.getInstance().getArrayType(myType);
1536            Type arrayAsmType = typeMapper.mapType(arrayType, JetTypeMapperMode.IMPL);
1537            v.newField(myClass, ACC_PRIVATE | ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, "$VALUES", arrayAsmType.getDescriptor(), null, null);
1538    
1539            iv.iconst(myEnumConstants.size());
1540            iv.newarray(myAsmType);
1541            iv.dup();
1542    
1543            for (JetEnumEntry enumConstant : myEnumConstants) {
1544                ordinal++;
1545    
1546                iv.dup();
1547                iv.iconst(ordinal);
1548    
1549                ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, enumConstant);
1550                assert classDescriptor != null;
1551                String implClass = typeMapper.mapType(classDescriptor.getDefaultType(), JetTypeMapperMode.IMPL).getInternalName();
1552    
1553                List<JetDelegationSpecifier> delegationSpecifiers = enumConstant.getDelegationSpecifiers();
1554                if (delegationSpecifiers.size() > 1) {
1555                    throw new UnsupportedOperationException("multiple delegation specifiers for enum constant not supported");
1556                }
1557    
1558                iv.anew(Type.getObjectType(implClass));
1559                iv.dup();
1560    
1561                iv.aconst(enumConstant.getName());
1562                iv.iconst(ordinal);
1563    
1564                if (delegationSpecifiers.size() == 1 && !enumEntryNeedSubclass(state.getBindingContext(), enumConstant)) {
1565                    JetDelegationSpecifier specifier = delegationSpecifiers.get(0);
1566                    if (specifier instanceof JetDelegatorToSuperCall) {
1567                        ResolvedCall<? extends CallableDescriptor> resolvedCall =
1568                                bindingContext.get(BindingContext.RESOLVED_CALL, ((JetDelegatorToSuperCall) specifier).getCalleeExpression());
1569                        assert resolvedCall != null : "Enum entry delegation specifier is unresolved: " + specifier.getText();
1570    
1571                        ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor();
1572                        CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor);
1573    
1574                        codegen.invokeMethodWithArguments(method, resolvedCall, null, StackValue.none());
1575                    }
1576                    else {
1577                        throw new UnsupportedOperationException("unsupported type of enum constant initializer: " + specifier);
1578                    }
1579                }
1580                else {
1581                    iv.invokespecial(implClass, "<init>", "(Ljava/lang/String;I)V");
1582                }
1583                iv.dup();
1584                iv.putstatic(myAsmType.getInternalName(), enumConstant.getName(), "L" + myAsmType.getInternalName() + ";");
1585                iv.astore(OBJECT_TYPE);
1586            }
1587            iv.putstatic(myAsmType.getInternalName(), "$VALUES", arrayAsmType.getDescriptor());
1588        }
1589    
1590        public static void generateInitializers(
1591                @NotNull ExpressionCodegen codegen, @NotNull List<JetDeclaration> declarations,
1592                @NotNull BindingContext bindingContext, @NotNull GenerationState state
1593        ) {
1594            JetTypeMapper typeMapper = state.getTypeMapper();
1595            for (JetDeclaration declaration : declarations) {
1596                if (declaration instanceof JetProperty) {
1597                    if (shouldInitializeProperty((JetProperty) declaration, typeMapper)) {
1598                        initializeProperty(codegen, bindingContext, (JetProperty) declaration);
1599                    }
1600                }
1601                else if (declaration instanceof JetClassInitializer) {
1602                    codegen.gen(((JetClassInitializer) declaration).getBody(), Type.VOID_TYPE);
1603                }
1604            }
1605        }
1606    
1607    
1608        public static void initializeProperty(
1609                @NotNull ExpressionCodegen codegen,
1610                @NotNull BindingContext bindingContext,
1611                @NotNull JetProperty property
1612        ) {
1613    
1614            PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(BindingContext.VARIABLE, property);
1615            assert propertyDescriptor != null;
1616    
1617            JetExpression initializer = property.getDelegateExpressionOrInitializer();
1618            assert initializer != null : "shouldInitializeProperty must return false if initializer is null";
1619    
1620            JetType jetType = getPropertyOrDelegateType(bindingContext, property, propertyDescriptor);
1621    
1622            StackValue.StackValueWithSimpleReceiver propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, null, MethodKind.INITIALIZER);
1623    
1624            if (!propValue.isStatic) {
1625                codegen.v.load(0, OBJECT_TYPE);
1626            }
1627    
1628            Type type = codegen.expressionType(initializer);
1629            if (jetType.isNullable()) {
1630                type = boxType(type);
1631            }
1632            codegen.gen(initializer, type);
1633    
1634            propValue.store(type, codegen.v);
1635        }
1636    
1637        public static boolean shouldWriteFieldInitializer(PropertyDescriptor descriptor, JetTypeMapper mapper) {
1638            //final field of primitive or String type
1639            if (!descriptor.isVar()) {
1640                Type type = mapper.mapType(descriptor.getType());
1641                return AsmUtil.isPrimitive(type) || "java.lang.String".equals(type.getClassName());
1642            }
1643            return false;
1644        }
1645    
1646        public static boolean shouldInitializeProperty(
1647                @NotNull JetProperty property,
1648                @NotNull JetTypeMapper typeMapper
1649        ) {
1650            JetExpression initializer = property.getDelegateExpressionOrInitializer();
1651            if (initializer == null) return false;
1652    
1653            CompileTimeConstant<?> compileTimeValue = typeMapper.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, initializer);
1654            if (compileTimeValue == null) return true;
1655    
1656            PropertyDescriptor propertyDescriptor = (PropertyDescriptor) typeMapper.getBindingContext().get(BindingContext.VARIABLE, property);
1657            assert propertyDescriptor != null;
1658    
1659            //TODO: OPTIMIZATION: don't initialize static final fields
1660    
1661            Object value = compileTimeValue.getValue();
1662            JetType jetType = getPropertyOrDelegateType(typeMapper.getBindingContext(), property, propertyDescriptor);
1663            Type type = typeMapper.mapType(jetType);
1664            return !skipDefaultValue(propertyDescriptor, value, type);
1665        }
1666    
1667        @NotNull
1668        private static JetType getPropertyOrDelegateType(@NotNull BindingContext bindingContext, @NotNull JetProperty property, @NotNull PropertyDescriptor descriptor) {
1669            JetExpression delegateExpression = property.getDelegateExpression();
1670            if (delegateExpression != null) {
1671                JetType delegateType = bindingContext.get(BindingContext.EXPRESSION_TYPE, delegateExpression);
1672                assert delegateType != null : "Type of delegate expression should be recorded";
1673                return delegateType;
1674            }
1675            return descriptor.getType();
1676        }
1677    
1678        private static boolean skipDefaultValue(@NotNull PropertyDescriptor propertyDescriptor, Object value, @NotNull Type type) {
1679            if (isPrimitive(type)) {
1680                if (!propertyDescriptor.getType().isNullable() && value instanceof Number) {
1681                    if (type == Type.INT_TYPE && ((Number) value).intValue() == 0) {
1682                        return true;
1683                    }
1684                    if (type == Type.BYTE_TYPE && ((Number) value).byteValue() == 0) {
1685                        return true;
1686                    }
1687                    if (type == Type.LONG_TYPE && ((Number) value).longValue() == 0L) {
1688                        return true;
1689                    }
1690                    if (type == Type.SHORT_TYPE && ((Number) value).shortValue() == 0) {
1691                        return true;
1692                    }
1693                    if (type == Type.DOUBLE_TYPE && ((Number) value).doubleValue() == 0d) {
1694                        return true;
1695                    }
1696                    if (type == Type.FLOAT_TYPE && ((Number) value).floatValue() == 0f) {
1697                        return true;
1698                    }
1699                }
1700                if (type == Type.BOOLEAN_TYPE && value instanceof Boolean && !((Boolean) value)) {
1701                    return true;
1702                }
1703                if (type == Type.CHAR_TYPE && value instanceof Character && ((Character) value) == 0) {
1704                    return true;
1705                }
1706            }
1707            else {
1708                if (value == null) {
1709                    return true;
1710                }
1711            }
1712            return false;
1713        }
1714    
1715        protected void generateDelegates(ClassDescriptor toClass, StackValue field) {
1716            for (DeclarationDescriptor declaration : descriptor.getDefaultType().getMemberScope().getAllDescriptors()) {
1717                if (declaration instanceof CallableMemberDescriptor) {
1718                    CallableMemberDescriptor callableMemberDescriptor = (CallableMemberDescriptor) declaration;
1719                    if (callableMemberDescriptor.getKind() == CallableMemberDescriptor.Kind.DELEGATION) {
1720                        Set<? extends CallableMemberDescriptor> overriddenDescriptors = callableMemberDescriptor.getOverriddenDescriptors();
1721                        for (CallableMemberDescriptor overriddenDescriptor : overriddenDescriptors) {
1722                            if (overriddenDescriptor.getContainingDeclaration() == toClass) {
1723                                if (declaration instanceof PropertyDescriptor) {
1724                                    propertyCodegen
1725                                            .genDelegate((PropertyDescriptor) declaration, (PropertyDescriptor) overriddenDescriptor, field);
1726                                }
1727                                else if (declaration instanceof FunctionDescriptor) {
1728                                    functionCodegen
1729                                            .genDelegate((FunctionDescriptor) declaration, (FunctionDescriptor) overriddenDescriptor, field);
1730                                }
1731                            }
1732                        }
1733                    }
1734                }
1735            }
1736        }
1737    
1738    
1739        /**
1740         * Return pairs of descriptors. First is member of this that should be implemented by delegating to trait,
1741         * second is member of trait that contain implementation.
1742         */
1743        private List<Pair<CallableMemberDescriptor, CallableMemberDescriptor>> getTraitImplementations(@NotNull ClassDescriptor classDescriptor) {
1744            List<Pair<CallableMemberDescriptor, CallableMemberDescriptor>> r = Lists.newArrayList();
1745    
1746            for (DeclarationDescriptor decl : classDescriptor.getDefaultType().getMemberScope().getAllDescriptors()) {
1747                if (!(decl instanceof CallableMemberDescriptor)) {
1748                    continue;
1749                }
1750    
1751                CallableMemberDescriptor callableMemberDescriptor = (CallableMemberDescriptor) decl;
1752                if (callableMemberDescriptor.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
1753                    continue;
1754                }
1755    
1756                Collection<CallableMemberDescriptor> overriddenDeclarations =
1757                        OverridingUtil.getOverriddenDeclarations(callableMemberDescriptor);
1758    
1759                Collection<CallableMemberDescriptor> filteredOverriddenDeclarations =
1760                        OverridingUtil.filterOverrides(Sets.newLinkedHashSet(overriddenDeclarations));
1761    
1762                int count = 0;
1763                CallableMemberDescriptor candidate = null;
1764    
1765                for (CallableMemberDescriptor overriddenDeclaration : filteredOverriddenDeclarations) {
1766                    if (isKindOf(overriddenDeclaration.getContainingDeclaration(), ClassKind.TRAIT) &&
1767                        overriddenDeclaration.getModality() != Modality.ABSTRACT) {
1768                        candidate = overriddenDeclaration;
1769                        count++;
1770                    }
1771                }
1772                if (candidate == null) {
1773                    continue;
1774                }
1775    
1776                assert count == 1 : "Ambiguous overridden declaration: " + callableMemberDescriptor.getName();
1777    
1778    
1779                Collection<JetType> superTypesOfSuperClass =
1780                        superClassType != null ? TypeUtils.getAllSupertypes(superClassType) : Collections.<JetType>emptySet();
1781                ReceiverParameterDescriptor expectedThisObject = candidate.getExpectedThisObject();
1782                assert expectedThisObject != null;
1783                JetType candidateType = expectedThisObject.getType();
1784                boolean implementedInSuperClass = superTypesOfSuperClass.contains(candidateType);
1785    
1786                if (!implementedInSuperClass) {
1787                    r.add(Pair.create(callableMemberDescriptor, candidate));
1788                }
1789            }
1790            return r;
1791        }
1792    
1793        public void addClassObjectPropertyToCopy(PropertyDescriptor descriptor, Object defaultValue) {
1794            if (classObjectPropertiesToCopy == null) {
1795                classObjectPropertiesToCopy = new ArrayList<PropertyAndDefaultValue>();
1796            }
1797            classObjectPropertiesToCopy.add(new PropertyAndDefaultValue(descriptor, defaultValue));
1798        }
1799    
1800        static class PropertyAndDefaultValue {
1801    
1802            PropertyAndDefaultValue(PropertyDescriptor propertyDescriptor, Object defaultValue) {
1803                this.propertyDescriptor = propertyDescriptor;
1804                this.defaultValue = defaultValue;
1805            }
1806    
1807            private PropertyDescriptor propertyDescriptor;
1808    
1809            private Object defaultValue;
1810    
1811    
1812        }
1813    
1814    }