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