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