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