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