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