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