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