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