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