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