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