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