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