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