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