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