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