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