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