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