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