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