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