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