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