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            boolean isObjectDeclaration = descriptor.getKind() == ClassKind.OBJECT && isNonLiteralObject(myClass) ;
940    
941            if (!isObjectDeclaration && !hasClassObject || isEnumClass) return;
942    
943            ClassDescriptor fieldTypeDescriptor = hasClassObject ? descriptor.getClassObjectDescriptor() : descriptor;
944            assert fieldTypeDescriptor != null;
945            StackValue.Field field = StackValue.singleton(fieldTypeDescriptor, typeMapper);
946            JetClassOrObject original;
947            if (hasClassObject) {
948                JetClassObject classObject = ((JetClass) myClass).getClassObject();
949                assert classObject != null : myClass.getText();
950                original = classObject.getObjectDeclaration();
951            }
952            else {
953                original = myClass;
954            }
955    
956            v.newField(original, ACC_PUBLIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null);
957    
958            if (!AsmUtil.isClassObjectWithBackingFieldsInOuter(fieldTypeDescriptor)) {
959                genInitSingleton(fieldTypeDescriptor, field);
960            }
961        }
962    
963        private void generateClassObjectBackingFieldCopies() {
964            if (classObjectPropertiesToCopy != null) {
965                for (PropertyAndDefaultValue propertyInfo : classObjectPropertiesToCopy) {
966                    PropertyDescriptor propertyDescriptor = propertyInfo.propertyDescriptor;
967    
968                    v.newField(null, ACC_STATIC | ACC_FINAL | ACC_PUBLIC, context.getFieldName(propertyDescriptor),
969                               typeMapper.mapType(propertyDescriptor).getDescriptor(), null, propertyInfo.defaultValue);
970    
971                    //This field are always static and final so if it has constant initializer don't do anything in clinit,
972                    //field would be initialized via default value in v.newField(...) - see JVM SPEC Ch.4
973                    if (state.getClassBuilderMode() == ClassBuilderMode.FULL && propertyInfo.defaultValue == null) {
974                        ExpressionCodegen codegen = createOrGetClInitCodegen();
975                        int classObjectIndex = putClassObjectInLocalVar(codegen);
976                        StackValue.local(classObjectIndex, OBJECT_TYPE).put(OBJECT_TYPE, codegen.v);
977                        copyFieldFromClassObject(propertyDescriptor);
978                    }
979                }
980            }
981        }
982    
983        private int putClassObjectInLocalVar(ExpressionCodegen codegen) {
984            FrameMap frameMap = codegen.myFrameMap;
985            ClassDescriptor classObjectDescriptor = descriptor.getClassObjectDescriptor();
986            int classObjectIndex = frameMap.getIndex(classObjectDescriptor);
987            if (classObjectIndex == -1) {
988                classObjectIndex = frameMap.enter(classObjectDescriptor, OBJECT_TYPE);
989                StackValue classObject = StackValue.singleton(classObjectDescriptor, typeMapper);
990                classObject.put(classObject.type, codegen.v);
991                StackValue.local(classObjectIndex, classObject.type).store(classObject.type, codegen.v);
992            }
993            return classObjectIndex;
994        }
995    
996        private void copyFieldFromClassObject(PropertyDescriptor propertyDescriptor) {
997            ExpressionCodegen codegen = createOrGetClInitCodegen();
998            StackValue property = codegen.intermediateValueForProperty(propertyDescriptor, false, null);
999            property.put(property.type, codegen.v);
1000            StackValue.Field field = StackValue.field(property.type, JvmClassName.byClassDescriptor(descriptor),
1001                                                      propertyDescriptor.getName().asString(), true);
1002            field.store(field.type, codegen.v);
1003        }
1004    
1005        protected void genInitSingleton(ClassDescriptor fieldTypeDescriptor, StackValue.Field field) {
1006            if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
1007                ConstructorDescriptor constructorDescriptor = DescriptorUtils.getConstructorOfSingletonObject(fieldTypeDescriptor);
1008                ExpressionCodegen codegen = createOrGetClInitCodegen();
1009                FunctionDescriptor fd = codegen.accessibleFunctionDescriptor(constructorDescriptor);
1010                generateMethodCallTo(fd, codegen.v);
1011                field.store(field.type, codegen.v);
1012            }
1013        }
1014    
1015        protected void generatePrimaryConstructor() {
1016            if (ignoreIfTraitOrAnnotation()) return;
1017    
1018            if (kind != OwnerKind.IMPLEMENTATION) {
1019                throw new IllegalStateException("incorrect kind for primary constructor: " + kind);
1020            }
1021    
1022            final MutableClosure closure = context.closure;
1023            ConstructorDescriptor constructorDescriptor = bindingContext.get(BindingContext.CONSTRUCTOR, myClass);
1024    
1025            ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor);
1026    
1027            if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
1028                lookupConstructorExpressionsInClosureIfPresent(constructorContext);
1029            }
1030    
1031            assert constructorDescriptor != null;
1032            final JvmMethodSignature constructorSignature = typeMapper.mapConstructorSignature(constructorDescriptor, closure);
1033    
1034            functionCodegen.generateMethod(null, constructorSignature, true, constructorDescriptor, constructorContext,
1035                       new FunctionGenerationStrategy.CodegenBased<ConstructorDescriptor>(state, constructorDescriptor) {
1036    
1037                           @NotNull
1038                           @Override
1039                           protected FrameMap createFrameMap(@NotNull JetTypeMapper typeMapper, @NotNull MethodContext context) {
1040                               return new ConstructorFrameMap(constructorSignature);
1041                           }
1042    
1043                           @Override
1044                           public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
1045                               generatePrimaryConstructorImpl(callableDescriptor, codegen, closure);
1046                           }
1047                       }
1048            );
1049    
1050            FunctionCodegen.generateDefaultIfNeeded(constructorContext, state, v, constructorSignature, constructorDescriptor,
1051                                                    OwnerKind.IMPLEMENTATION, DefaultParameterValueLoader.DEFAULT);
1052    
1053            CallableMethod callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor, closure);
1054            FunctionCodegen.generateConstructorWithoutParametersIfNeeded(state, callableMethod, constructorDescriptor, v);
1055    
1056            if (isClassObject(descriptor)) {
1057                context.recordSyntheticAccessorIfNeeded(constructorDescriptor, typeMapper);
1058            }
1059        }
1060    
1061        private void generatePrimaryConstructorImpl(
1062                @Nullable ConstructorDescriptor constructorDescriptor,
1063                @NotNull ExpressionCodegen codegen,
1064                @Nullable MutableClosure closure
1065        ) {
1066            List<ValueParameterDescriptor> paramDescrs = constructorDescriptor != null
1067                                                         ? constructorDescriptor.getValueParameters()
1068                                                         : Collections.<ValueParameterDescriptor>emptyList();
1069    
1070            InstructionAdapter iv = codegen.v;
1071    
1072            JvmClassName className = JvmClassName.byType(classAsmType);
1073    
1074            if (superCall == null) {
1075                genSimpleSuperCall(iv);
1076            }
1077            else if (superCall instanceof JetDelegatorToSuperClass) {
1078                genSuperCallToDelegatorToSuperClass(iv);
1079            }
1080            else {
1081                generateDelegatorToConstructorCall(iv, codegen, constructorDescriptor);
1082            }
1083    
1084            if (closure != null) {
1085                List<FieldInfo> argsFromClosure = ClosureCodegen.calculateConstructorParameters(typeMapper, closure, classAsmType);
1086                int k = 1;
1087                for (FieldInfo info : argsFromClosure) {
1088                    k = AsmUtil.genAssignInstanceFieldFromParam(info, k, iv);
1089                }
1090            }
1091    
1092            int n = 0;
1093            for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) {
1094                if (specifier == superCall) {
1095                    continue;
1096                }
1097    
1098                if (specifier instanceof JetDelegatorByExpressionSpecifier) {
1099                    genCallToDelegatorByExpressionSpecifier(iv, codegen, classAsmType, className, n++, specifier);
1100                }
1101            }
1102    
1103            int curParam = 0;
1104            List<JetParameter> constructorParameters = getPrimaryConstructorParameters();
1105            for (JetParameter parameter : constructorParameters) {
1106                if (parameter.getValOrVarNode() != null) {
1107                    VariableDescriptor descriptor = paramDescrs.get(curParam);
1108                    Type type = typeMapper.mapType(descriptor);
1109                    iv.load(0, classAsmType);
1110                    iv.load(codegen.myFrameMap.getIndex(descriptor), type);
1111                    iv.putfield(classAsmType.getInternalName(),
1112                                context.getFieldName(DescriptorUtils.getPropertyDescriptor(parameter, bindingContext)),
1113                                type.getDescriptor());
1114                }
1115                curParam++;
1116            }
1117    
1118            boolean generateInitializerInOuter = isClassObjectWithBackingFieldsInOuter(descriptor);
1119            if (generateInitializerInOuter) {
1120                ImplementationBodyCodegen parentCodegen = getParentBodyCodegen(this);
1121                //generate object$
1122                parentCodegen.genInitSingleton(descriptor, StackValue.singleton(descriptor, typeMapper));
1123                parentCodegen.generateInitializers(parentCodegen.createOrGetClInitCodegen(),
1124                                                   myClass.getDeclarations(), bindingContext, state);
1125            } else {
1126                generateInitializers(codegen, myClass.getDeclarations(), bindingContext, state);
1127            }
1128    
1129    
1130            iv.visitInsn(RETURN);
1131        }
1132    
1133        private void genSuperCallToDelegatorToSuperClass(InstructionAdapter iv) {
1134            iv.load(0, superClassAsmType);
1135            JetType superType = bindingContext.get(BindingContext.TYPE, superCall.getTypeReference());
1136            List<Type> parameterTypes = new ArrayList<Type>();
1137            assert superType != null;
1138            ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
1139            if (CodegenBinding.hasThis0(bindingContext, superClassDescriptor)) {
1140                iv.load(1, OBJECT_TYPE);
1141                parameterTypes.add(typeMapper.mapType(
1142                        enclosingClassDescriptor(bindingContext, descriptor)));
1143            }
1144            Method superCallMethod = new Method("<init>", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()]));
1145            //noinspection ConstantConditions
1146            iv.invokespecial(typeMapper.mapType(superClassDescriptor).getInternalName(), "<init>",
1147                             superCallMethod.getDescriptor());
1148        }
1149    
1150        private void genSimpleSuperCall(InstructionAdapter iv) {
1151            iv.load(0, superClassAsmType);
1152            if (descriptor.getKind() == ClassKind.ENUM_CLASS || descriptor.getKind() == ClassKind.ENUM_ENTRY) {
1153                iv.load(1, JAVA_STRING_TYPE);
1154                iv.load(2, Type.INT_TYPE);
1155                iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "(Ljava/lang/String;I)V");
1156            }
1157            else {
1158                iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "()V");
1159            }
1160        }
1161    
1162        private void genCallToDelegatorByExpressionSpecifier(
1163                InstructionAdapter iv,
1164                ExpressionCodegen codegen,
1165                Type classType,
1166                JvmClassName className,
1167                int n,
1168                JetDelegationSpecifier specifier
1169        ) {
1170            JetExpression expression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression();
1171            PropertyDescriptor propertyDescriptor = null;
1172            if (expression instanceof JetSimpleNameExpression) {
1173                ResolvedCall<? extends CallableDescriptor> call = bindingContext.get(BindingContext.RESOLVED_CALL, expression);
1174                if (call != null) {
1175                    CallableDescriptor callResultingDescriptor = call.getResultingDescriptor();
1176                    if (callResultingDescriptor instanceof ValueParameterDescriptor) {
1177                        ValueParameterDescriptor valueParameterDescriptor = (ValueParameterDescriptor) callResultingDescriptor;
1178                        // constructor parameter
1179                        if (valueParameterDescriptor.getContainingDeclaration() instanceof ConstructorDescriptor) {
1180                            // constructor of my class
1181                            if (valueParameterDescriptor.getContainingDeclaration().getContainingDeclaration() == descriptor) {
1182                                propertyDescriptor = bindingContext.get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, valueParameterDescriptor);
1183                            }
1184                        }
1185                    }
1186    
1187                    // todo: when and if frontend will allow properties defined not as constructor parameters to be used in delegation specifier
1188                }
1189            }
1190    
1191            JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference());
1192            assert superType != null;
1193    
1194            ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
1195            assert superClassDescriptor != null;
1196    
1197            StackValue field;
1198            if (propertyDescriptor != null &&
1199                !propertyDescriptor.isVar() &&
1200                Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor))) {
1201                // final property with backing field
1202                field = StackValue.field(typeMapper.mapType(propertyDescriptor.getType()), className,
1203                                         propertyDescriptor.getName().asString(), false);
1204            }
1205            else {
1206                iv.load(0, classType);
1207                codegen.genToJVMStack(expression);
1208    
1209                String delegateField = "$delegate_" + n;
1210                Type fieldType = typeMapper.mapType(superClassDescriptor);
1211                String fieldDesc = fieldType.getDescriptor();
1212    
1213                v.newField(specifier, ACC_PRIVATE|ACC_FINAL|ACC_SYNTHETIC, delegateField, fieldDesc, /*TODO*/null, null);
1214    
1215                field = StackValue.field(fieldType, className, delegateField, false);
1216                field.store(fieldType, iv);
1217            }
1218    
1219            generateDelegates(superClassDescriptor, field);
1220        }
1221    
1222        private void lookupConstructorExpressionsInClosureIfPresent(final ConstructorContext constructorContext) {
1223            JetVisitorVoid visitor = new JetVisitorVoid() {
1224                @Override
1225                public void visitJetElement(JetElement e) {
1226                    e.acceptChildren(this);
1227                }
1228    
1229                @Override
1230                public void visitSimpleNameExpression(JetSimpleNameExpression expr) {
1231                    DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expr);
1232                    if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) {
1233                        ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) constructorContext.getContextDescriptor();
1234                        for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
1235                            //noinspection ConstantConditions
1236                            if (descriptor.equals(parameterDescriptor)) {
1237                                return;
1238                            }
1239                        }
1240                        constructorContext.lookupInContext(descriptor, null, state, true);
1241                    } else if (isLocalNamedFun(descriptor)) {
1242                        assert descriptor != null;
1243                        MutableClassDescriptor classDescriptor =
1244                                (MutableClassDescriptor) constructorContext.getParentContext().getContextDescriptor();
1245    
1246                        for (CallableMemberDescriptor memberDescriptor : classDescriptor.getAllCallableMembers()) {
1247                            if (descriptor.equals(memberDescriptor)) {
1248                                return;
1249                            }
1250                        }
1251                        constructorContext.lookupInContext(descriptor, null, state, true);
1252                    }
1253                }
1254    
1255                @Override
1256                public void visitThisExpression(JetThisExpression expression) {
1257                    DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference());
1258                    if (descriptor instanceof ClassDescriptor) {
1259                        // @todo for now all our classes are inner so no need to lookup this. change it when we have real inners
1260                    }
1261                    else {
1262                        assert descriptor instanceof CallableDescriptor;
1263                        if (context.getCallableDescriptorWithReceiver() != descriptor) {
1264                            context.lookupInContext(descriptor, null, state, false);
1265                        }
1266                    }
1267                }
1268            };
1269    
1270            for (JetDeclaration declaration : myClass.getDeclarations()) {
1271                if (declaration instanceof JetProperty) {
1272                    JetProperty property = (JetProperty) declaration;
1273                    JetExpression initializer = property.getInitializer();
1274                    if (initializer != null) {
1275                        initializer.accept(visitor);
1276                    }
1277                }
1278                else if (declaration instanceof JetClassInitializer) {
1279                    JetClassInitializer initializer = (JetClassInitializer) declaration;
1280                    initializer.accept(visitor);
1281                }
1282            }
1283    
1284            for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) {
1285                if (specifier != superCall) {
1286                    if (specifier instanceof JetDelegatorByExpressionSpecifier) {
1287                        JetExpression delegateExpression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression();
1288                        assert delegateExpression != null;
1289                        delegateExpression.accept(visitor);
1290                    }
1291                }
1292                else {
1293                    if (superCall instanceof JetDelegatorToSuperCall) {
1294                        JetValueArgumentList argumentList = ((JetDelegatorToSuperCall) superCall).getValueArgumentList();
1295                        if (argumentList != null) {
1296                            argumentList.accept(visitor);
1297                        }
1298                    }
1299                }
1300            }
1301        }
1302    
1303        private boolean ignoreIfTraitOrAnnotation() {
1304            if (myClass instanceof JetClass) {
1305                JetClass aClass = (JetClass) myClass;
1306                if (aClass.isTrait()) {
1307                    return true;
1308                }
1309                if (aClass.isAnnotation()) {
1310                    return true;
1311                }
1312            }
1313            return false;
1314        }
1315    
1316        private void generateTraitMethods() {
1317            if (JetPsiUtil.isTrait(myClass)) {
1318                return;
1319            }
1320    
1321            for (Pair<CallableMemberDescriptor, CallableMemberDescriptor> needDelegates : getTraitImplementations(descriptor)) {
1322                if (needDelegates.second instanceof SimpleFunctionDescriptor) {
1323                    generateDelegationToTraitImpl((FunctionDescriptor) needDelegates.second, (FunctionDescriptor) needDelegates.first);
1324                }
1325                else if (needDelegates.second instanceof PropertyDescriptor) {
1326                    PropertyDescriptor property = (PropertyDescriptor) needDelegates.second;
1327                    List<PropertyAccessorDescriptor> inheritedAccessors = ((PropertyDescriptor) needDelegates.first).getAccessors();
1328                    for (PropertyAccessorDescriptor accessor : property.getAccessors()) {
1329                        for (PropertyAccessorDescriptor inheritedAccessor : inheritedAccessors) {
1330                            if (inheritedAccessor.getClass() == accessor.getClass()) { // same accessor kind
1331                                generateDelegationToTraitImpl(accessor, inheritedAccessor);
1332                            }
1333                        }
1334                    }
1335                }
1336            }
1337        }
1338    
1339    
1340        private void generateDelegationToTraitImpl(final @NotNull FunctionDescriptor fun, @NotNull FunctionDescriptor inheritedFun) {
1341            DeclarationDescriptor containingDeclaration = fun.getContainingDeclaration();
1342            if (!(containingDeclaration instanceof ClassDescriptor)) {
1343                return;
1344            }
1345    
1346            ClassDescriptor containingClass = (ClassDescriptor) containingDeclaration;
1347            if (containingClass.getKind() != ClassKind.TRAIT) {
1348                return;
1349            }
1350    
1351            int flags = ACC_PUBLIC; // TODO.
1352    
1353            TraitImplDelegateInfo delegateInfo = getTraitImplDelegateInfo(fun);
1354            Method methodToGenerate = delegateInfo.methodToGenerate;
1355            Method methodInTrait = delegateInfo.methodInTrait;
1356    
1357            PsiElement origin = descriptorToDeclaration(bindingContext, fun);
1358            MethodVisitor mv = v.newMethod(origin, flags, methodToGenerate.getName(), methodToGenerate.getDescriptor(), null, null);
1359            AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(fun);
1360    
1361            if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
1362                genStubCode(mv);
1363            }
1364            else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
1365                writeAnnotationForDelegateToTraitImpl(fun, inheritedFun, mv);
1366                functionCodegen.generateMethodParametersAnnotations(mv, fun, typeMapper.mapSignature(fun));
1367    
1368                Type returnType = methodToGenerate.getReturnType();
1369    
1370                mv.visitCode();
1371                FrameMap frameMap = context.prepareFrame(typeMapper);
1372                ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, returnType, context.intoFunction(inheritedFun), state);
1373                codegen.generateThisOrOuter(descriptor, false);    // ??? wouldn't it be addClosureToConstructorParameters good idea to put it?
1374    
1375                Type[] argTypes = methodToGenerate.getArgumentTypes();
1376                Type[] originalArgTypes = methodInTrait.getArgumentTypes();
1377    
1378                InstructionAdapter iv = new InstructionAdapter(mv);
1379                iv.load(0, OBJECT_TYPE);
1380                for (int i = 0, reg = 1; i < argTypes.length; i++) {
1381                    StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
1382                    //noinspection AssignmentToForLoopParameter
1383                    reg += argTypes[i].getSize();
1384                }
1385    
1386                Type type = getTraitImplThisParameterType(containingClass, typeMapper);
1387                String functionDescriptor = methodInTrait.getDescriptor().replace("(", "(" + type.getDescriptor());
1388    
1389                Type tImplType = typeMapper.mapType(containingClass.getDefaultType(), JetTypeMapperMode.TRAIT_IMPL);
1390    
1391                iv.invokestatic(tImplType.getInternalName(), methodToGenerate.getName(), functionDescriptor);
1392                StackValue.onStack(methodInTrait.getReturnType()).put(returnType, iv);
1393                iv.areturn(returnType);
1394    
1395                FunctionCodegen.endVisit(iv, "trait method", callableDescriptorToDeclaration(bindingContext, fun));
1396            }
1397    
1398            FunctionCodegen.generateBridgeIfNeeded(context, state, v, methodToGenerate, fun);
1399        }
1400    
1401        private static class TraitImplDelegateInfo {
1402            private final Method methodToGenerate;
1403            private final Method methodInTrait;
1404    
1405            private TraitImplDelegateInfo(@NotNull Method methodToGenerate, @NotNull Method methodInTrait) {
1406                this.methodToGenerate = methodToGenerate;
1407                this.methodInTrait = methodInTrait;
1408            }
1409        }
1410    
1411        @NotNull
1412        private TraitImplDelegateInfo getTraitImplDelegateInfo(@NotNull FunctionDescriptor fun) {
1413            if (fun instanceof PropertyAccessorDescriptor) {
1414                PropertyDescriptor property = ((PropertyAccessorDescriptor) fun).getCorrespondingProperty();
1415                PropertyDescriptor original = property.getOriginal();
1416                if (fun instanceof PropertyGetterDescriptor) {
1417                    JvmPropertyAccessorSignature toGenerate = typeMapper.mapGetterSignature(property, OwnerKind.IMPLEMENTATION);
1418                    JvmPropertyAccessorSignature inTrait = typeMapper.mapGetterSignature(original, OwnerKind.IMPLEMENTATION);
1419                    return new TraitImplDelegateInfo(
1420                            toGenerate.getAsmMethod(), inTrait.getAsmMethod());
1421                }
1422                else if (fun instanceof PropertySetterDescriptor) {
1423                    JvmPropertyAccessorSignature toGenerate = typeMapper.mapSetterSignature(property, OwnerKind.IMPLEMENTATION);
1424                    JvmPropertyAccessorSignature inTrait = typeMapper.mapSetterSignature(original, OwnerKind.IMPLEMENTATION);
1425                    return new TraitImplDelegateInfo(
1426                            toGenerate.getAsmMethod(), inTrait.getAsmMethod());
1427                }
1428                else {
1429                    throw new IllegalStateException("Accessor is neither getter, nor setter, what is it? " + fun);
1430                }
1431            }
1432            else {
1433                Method function = typeMapper.mapSignature(fun).getAsmMethod();
1434                Method functionOriginal = typeMapper.mapSignature(fun.getOriginal()).getAsmMethod();
1435                return new TraitImplDelegateInfo(function, functionOriginal);
1436            }
1437        }
1438    
1439        private void writeAnnotationForDelegateToTraitImpl(
1440                @NotNull FunctionDescriptor fun,
1441                @NotNull FunctionDescriptor inheritedFun,
1442                @NotNull MethodVisitor mv
1443        ) {
1444            JvmMethodSignature jvmSignature = typeMapper.mapSignature(inheritedFun, true, OwnerKind.IMPLEMENTATION);
1445            JetMethodAnnotationWriter aw = JetMethodAnnotationWriter.visitAnnotation(mv);
1446            int kotlinFlags = getFlagsForVisibility(fun.getVisibility());
1447            if (fun instanceof PropertyAccessorDescriptor) {
1448                kotlinFlags |= JvmStdlibNames.FLAG_PROPERTY_BIT;
1449                aw.writeTypeParameters(jvmSignature.getKotlinTypeParameter());
1450                aw.writePropertyType(jvmSignature.getKotlinReturnType());
1451            }
1452            else {
1453                aw.writeTypeParameters(jvmSignature.getKotlinTypeParameter());
1454                aw.writeReturnType(jvmSignature.getKotlinReturnType());
1455            }
1456            kotlinFlags |= DescriptorKindUtils.kindToFlags(inheritedFun.getKind());
1457            aw.writeFlags(kotlinFlags);
1458            aw.visitEnd();
1459        }
1460    
1461        private void generateDelegatorToConstructorCall(
1462                InstructionAdapter iv, ExpressionCodegen codegen,
1463                ConstructorDescriptor constructorDescriptor
1464        ) {
1465            ClassDescriptor classDecl = constructorDescriptor.getContainingDeclaration();
1466    
1467            iv.load(0, OBJECT_TYPE);
1468    
1469            if (classDecl.getKind() == ClassKind.ENUM_CLASS || classDecl.getKind() == ClassKind.ENUM_ENTRY) {
1470                iv.load(1, OBJECT_TYPE);
1471                iv.load(2, Type.INT_TYPE);
1472            }
1473    
1474            CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor, context.closure);
1475    
1476            ResolvedCall<? extends CallableDescriptor> resolvedCall =
1477                    bindingContext.get(BindingContext.RESOLVED_CALL, ((JetCallElement) superCall).getCalleeExpression());
1478            assert resolvedCall != null;
1479            ConstructorDescriptor superConstructor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor();
1480    
1481            //noinspection SuspiciousMethodCalls
1482            CalculatedClosure closureForSuper = bindingContext.get(CLOSURE, superConstructor.getContainingDeclaration());
1483            CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor, closureForSuper);
1484    
1485            if (closureForSuper != null && closureForSuper.getCaptureThis() != null) {
1486                iv.load(((ConstructorFrameMap)codegen.myFrameMap).getOuterThisIndex(), OBJECT_TYPE);
1487            }
1488    
1489            if (myClass instanceof JetObjectDeclaration &&
1490                superCall instanceof JetDelegatorToSuperCall &&
1491                ((JetObjectDeclaration) myClass).isObjectLiteral()) {
1492                int nextVar = findFirstSuperArgument(method);
1493                for (Type t : superCallable.getSignature().getAsmMethod().getArgumentTypes()) {
1494                    iv.load(nextVar, t);
1495                    nextVar += t.getSize();
1496                }
1497                superCallable.invokeWithNotNullAssertion(codegen.v, state, resolvedCall);
1498            }
1499            else {
1500                codegen.invokeMethodWithArguments(superCallable, resolvedCall, null, StackValue.none());
1501            }
1502        }
1503    
1504        private static int findFirstSuperArgument(CallableMethod method) {
1505            List<JvmMethodParameterSignature> types = method.getSignature().getKotlinParameterTypes();
1506            int i = 0;
1507            for (JvmMethodParameterSignature type : types) {
1508                if (type.getKind() == JvmMethodParameterKind.SUPER_CALL_PARAM) {
1509                    return i + 1; // because of this
1510                }
1511                i += type.getAsmType().getSize();
1512            }
1513            return -1;
1514        }
1515    
1516        @Override
1517        protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration) {
1518            if (declaration instanceof JetEnumEntry) {
1519                String name = declaration.getName();
1520                String desc = "L" + classAsmType.getInternalName() + ";";
1521                v.newField(declaration, ACC_PUBLIC | ACC_ENUM | ACC_STATIC | ACC_FINAL, name, desc, null, null);
1522                myEnumConstants.add((JetEnumEntry) declaration);
1523            }
1524    
1525            super.generateDeclaration(propertyCodegen, declaration);
1526        }
1527    
1528        private final List<JetEnumEntry> myEnumConstants = new ArrayList<JetEnumEntry>();
1529    
1530        private void initializeEnumConstants(ExpressionCodegen codegen) {
1531            InstructionAdapter iv = codegen.v;
1532            int ordinal = -1;
1533            JetType myType = descriptor.getDefaultType();
1534            Type myAsmType = typeMapper.mapType(myType, JetTypeMapperMode.IMPL);
1535    
1536            assert myEnumConstants.size() > 0;
1537            JetType arrayType = KotlinBuiltIns.getInstance().getArrayType(myType);
1538            Type arrayAsmType = typeMapper.mapType(arrayType, JetTypeMapperMode.IMPL);
1539            v.newField(myClass, ACC_PRIVATE | ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, "$VALUES", arrayAsmType.getDescriptor(), null, null);
1540    
1541            iv.iconst(myEnumConstants.size());
1542            iv.newarray(myAsmType);
1543            iv.dup();
1544    
1545            for (JetEnumEntry enumConstant : myEnumConstants) {
1546                ordinal++;
1547    
1548                iv.dup();
1549                iv.iconst(ordinal);
1550    
1551                ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, enumConstant);
1552                assert classDescriptor != null;
1553                String implClass = typeMapper.mapType(classDescriptor.getDefaultType(), JetTypeMapperMode.IMPL).getInternalName();
1554    
1555                List<JetDelegationSpecifier> delegationSpecifiers = enumConstant.getDelegationSpecifiers();
1556                if (delegationSpecifiers.size() > 1) {
1557                    throw new UnsupportedOperationException("multiple delegation specifiers for enum constant not supported");
1558                }
1559    
1560                iv.anew(Type.getObjectType(implClass));
1561                iv.dup();
1562    
1563                iv.aconst(enumConstant.getName());
1564                iv.iconst(ordinal);
1565    
1566                if (delegationSpecifiers.size() == 1 && !enumEntryNeedSubclass(state.getBindingContext(), enumConstant)) {
1567                    JetDelegationSpecifier specifier = delegationSpecifiers.get(0);
1568                    if (specifier instanceof JetDelegatorToSuperCall) {
1569                        ResolvedCall<? extends CallableDescriptor> resolvedCall =
1570                                bindingContext.get(BindingContext.RESOLVED_CALL, ((JetDelegatorToSuperCall) specifier).getCalleeExpression());
1571                        assert resolvedCall != null : "Enum entry delegation specifier is unresolved: " + specifier.getText();
1572    
1573                        ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor();
1574                        CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor);
1575    
1576                        codegen.invokeMethodWithArguments(method, resolvedCall, null, StackValue.none());
1577                    }
1578                    else {
1579                        throw new UnsupportedOperationException("unsupported type of enum constant initializer: " + specifier);
1580                    }
1581                }
1582                else {
1583                    iv.invokespecial(implClass, "<init>", "(Ljava/lang/String;I)V");
1584                }
1585                iv.dup();
1586                iv.putstatic(myAsmType.getInternalName(), enumConstant.getName(), "L" + myAsmType.getInternalName() + ";");
1587                iv.astore(OBJECT_TYPE);
1588            }
1589            iv.putstatic(myAsmType.getInternalName(), "$VALUES", arrayAsmType.getDescriptor());
1590        }
1591    
1592        public static void generateInitializers(
1593                @NotNull ExpressionCodegen codegen, @NotNull List<JetDeclaration> declarations,
1594                @NotNull BindingContext bindingContext, @NotNull GenerationState state
1595        ) {
1596            JetTypeMapper typeMapper = state.getTypeMapper();
1597            for (JetDeclaration declaration : declarations) {
1598                if (declaration instanceof JetProperty) {
1599                    if (shouldInitializeProperty((JetProperty) declaration, typeMapper)) {
1600                        initializeProperty(codegen, bindingContext, (JetProperty) declaration);
1601                    }
1602                }
1603                else if (declaration instanceof JetClassInitializer) {
1604                    codegen.gen(((JetClassInitializer) declaration).getBody(), Type.VOID_TYPE);
1605                }
1606            }
1607        }
1608    
1609    
1610        public static void initializeProperty(
1611                @NotNull ExpressionCodegen codegen,
1612                @NotNull BindingContext bindingContext,
1613                @NotNull JetProperty property
1614        ) {
1615    
1616            PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(BindingContext.VARIABLE, property);
1617            assert propertyDescriptor != null;
1618    
1619            JetExpression initializer = property.getDelegateExpressionOrInitializer();
1620            assert initializer != null : "shouldInitializeProperty must return false if initializer is null";
1621    
1622            JetType jetType = getPropertyOrDelegateType(bindingContext, property, propertyDescriptor);
1623    
1624            StackValue.StackValueWithSimpleReceiver propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, null, MethodKind.INITIALIZER);
1625    
1626            if (!propValue.isStatic) {
1627                codegen.v.load(0, OBJECT_TYPE);
1628            }
1629    
1630            Type type = codegen.expressionType(initializer);
1631            if (jetType.isNullable()) {
1632                type = boxType(type);
1633            }
1634            codegen.gen(initializer, type);
1635    
1636            propValue.store(type, codegen.v);
1637        }
1638    
1639        public static boolean shouldWriteFieldInitializer(PropertyDescriptor descriptor, JetTypeMapper mapper) {
1640            //final field of primitive or String type
1641            if (!descriptor.isVar()) {
1642                Type type = mapper.mapType(descriptor.getType());
1643                return AsmUtil.isPrimitive(type) || "java.lang.String".equals(type.getClassName());
1644            }
1645            return false;
1646        }
1647    
1648        public static boolean shouldInitializeProperty(
1649                @NotNull JetProperty property,
1650                @NotNull JetTypeMapper typeMapper
1651        ) {
1652            JetExpression initializer = property.getDelegateExpressionOrInitializer();
1653            if (initializer == null) return false;
1654    
1655            CompileTimeConstant<?> compileTimeValue = typeMapper.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, initializer);
1656            if (compileTimeValue == null) return true;
1657    
1658            PropertyDescriptor propertyDescriptor = (PropertyDescriptor) typeMapper.getBindingContext().get(BindingContext.VARIABLE, property);
1659            assert propertyDescriptor != null;
1660    
1661            //TODO: OPTIMIZATION: don't initialize static final fields
1662    
1663            Object value = compileTimeValue.getValue();
1664            JetType jetType = getPropertyOrDelegateType(typeMapper.getBindingContext(), property, propertyDescriptor);
1665            Type type = typeMapper.mapType(jetType);
1666            return !skipDefaultValue(propertyDescriptor, value, type);
1667        }
1668    
1669        @NotNull
1670        private static JetType getPropertyOrDelegateType(@NotNull BindingContext bindingContext, @NotNull JetProperty property, @NotNull PropertyDescriptor descriptor) {
1671            JetExpression delegateExpression = property.getDelegateExpression();
1672            if (delegateExpression != null) {
1673                JetType delegateType = bindingContext.get(BindingContext.EXPRESSION_TYPE, delegateExpression);
1674                assert delegateType != null : "Type of delegate expression should be recorded";
1675                return delegateType;
1676            }
1677            return descriptor.getType();
1678        }
1679    
1680        private static boolean skipDefaultValue(@NotNull PropertyDescriptor propertyDescriptor, Object value, @NotNull Type type) {
1681            if (isPrimitive(type)) {
1682                if (!propertyDescriptor.getType().isNullable() && value instanceof Number) {
1683                    if (type == Type.INT_TYPE && ((Number) value).intValue() == 0) {
1684                        return true;
1685                    }
1686                    if (type == Type.BYTE_TYPE && ((Number) value).byteValue() == 0) {
1687                        return true;
1688                    }
1689                    if (type == Type.LONG_TYPE && ((Number) value).longValue() == 0L) {
1690                        return true;
1691                    }
1692                    if (type == Type.SHORT_TYPE && ((Number) value).shortValue() == 0) {
1693                        return true;
1694                    }
1695                    if (type == Type.DOUBLE_TYPE && ((Number) value).doubleValue() == 0d) {
1696                        return true;
1697                    }
1698                    if (type == Type.FLOAT_TYPE && ((Number) value).floatValue() == 0f) {
1699                        return true;
1700                    }
1701                }
1702                if (type == Type.BOOLEAN_TYPE && value instanceof Boolean && !((Boolean) value)) {
1703                    return true;
1704                }
1705                if (type == Type.CHAR_TYPE && value instanceof Character && ((Character) value) == 0) {
1706                    return true;
1707                }
1708            }
1709            else {
1710                if (value == null) {
1711                    return true;
1712                }
1713            }
1714            return false;
1715        }
1716    
1717        protected void generateDelegates(ClassDescriptor toClass, StackValue field) {
1718            for (DeclarationDescriptor declaration : descriptor.getDefaultType().getMemberScope().getAllDescriptors()) {
1719                if (declaration instanceof CallableMemberDescriptor) {
1720                    CallableMemberDescriptor callableMemberDescriptor = (CallableMemberDescriptor) declaration;
1721                    if (callableMemberDescriptor.getKind() == CallableMemberDescriptor.Kind.DELEGATION) {
1722                        Set<? extends CallableMemberDescriptor> overriddenDescriptors = callableMemberDescriptor.getOverriddenDescriptors();
1723                        for (CallableMemberDescriptor overriddenDescriptor : overriddenDescriptors) {
1724                            if (overriddenDescriptor.getContainingDeclaration() == toClass) {
1725                                if (declaration instanceof PropertyDescriptor) {
1726                                    propertyCodegen
1727                                            .genDelegate((PropertyDescriptor) declaration, (PropertyDescriptor) overriddenDescriptor, field);
1728                                }
1729                                else if (declaration instanceof FunctionDescriptor) {
1730                                    functionCodegen
1731                                            .genDelegate((FunctionDescriptor) declaration, (FunctionDescriptor) overriddenDescriptor, field);
1732                                }
1733                            }
1734                        }
1735                    }
1736                }
1737            }
1738        }
1739    
1740    
1741        /**
1742         * Return pairs of descriptors. First is member of this that should be implemented by delegating to trait,
1743         * second is member of trait that contain implementation.
1744         */
1745        private List<Pair<CallableMemberDescriptor, CallableMemberDescriptor>> getTraitImplementations(@NotNull ClassDescriptor classDescriptor) {
1746            List<Pair<CallableMemberDescriptor, CallableMemberDescriptor>> r = Lists.newArrayList();
1747    
1748            for (DeclarationDescriptor decl : classDescriptor.getDefaultType().getMemberScope().getAllDescriptors()) {
1749                if (!(decl instanceof CallableMemberDescriptor)) {
1750                    continue;
1751                }
1752    
1753                CallableMemberDescriptor callableMemberDescriptor = (CallableMemberDescriptor) decl;
1754                if (callableMemberDescriptor.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
1755                    continue;
1756                }
1757    
1758                Collection<CallableMemberDescriptor> overriddenDeclarations =
1759                        OverridingUtil.getOverriddenDeclarations(callableMemberDescriptor);
1760    
1761                Collection<CallableMemberDescriptor> filteredOverriddenDeclarations =
1762                        OverridingUtil.filterOverrides(Sets.newLinkedHashSet(overriddenDeclarations));
1763    
1764                int count = 0;
1765                CallableMemberDescriptor candidate = null;
1766    
1767                for (CallableMemberDescriptor overriddenDeclaration : filteredOverriddenDeclarations) {
1768                    if (isKindOf(overriddenDeclaration.getContainingDeclaration(), ClassKind.TRAIT) &&
1769                        overriddenDeclaration.getModality() != Modality.ABSTRACT) {
1770                        candidate = overriddenDeclaration;
1771                        count++;
1772                    }
1773                }
1774                if (candidate == null) {
1775                    continue;
1776                }
1777    
1778                assert count == 1 : "Ambiguous overridden declaration: " + callableMemberDescriptor.getName();
1779    
1780    
1781                Collection<JetType> superTypesOfSuperClass =
1782                        superClassType != null ? TypeUtils.getAllSupertypes(superClassType) : Collections.<JetType>emptySet();
1783                ReceiverParameterDescriptor expectedThisObject = candidate.getExpectedThisObject();
1784                assert expectedThisObject != null;
1785                JetType candidateType = expectedThisObject.getType();
1786                boolean implementedInSuperClass = superTypesOfSuperClass.contains(candidateType);
1787    
1788                if (!implementedInSuperClass) {
1789                    r.add(Pair.create(callableMemberDescriptor, candidate));
1790                }
1791            }
1792            return r;
1793        }
1794    
1795        public void addClassObjectPropertyToCopy(PropertyDescriptor descriptor, Object defaultValue) {
1796            if (classObjectPropertiesToCopy == null) {
1797                classObjectPropertiesToCopy = new ArrayList<PropertyAndDefaultValue>();
1798            }
1799            classObjectPropertiesToCopy.add(new PropertyAndDefaultValue(descriptor, defaultValue));
1800        }
1801    
1802        static class PropertyAndDefaultValue {
1803    
1804            PropertyAndDefaultValue(PropertyDescriptor propertyDescriptor, Object defaultValue) {
1805                this.propertyDescriptor = propertyDescriptor;
1806                this.defaultValue = defaultValue;
1807            }
1808    
1809            private PropertyDescriptor propertyDescriptor;
1810    
1811            private Object defaultValue;
1812    
1813    
1814        }
1815    
1816    }