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.ClassData;
063    import org.jetbrains.kotlin.serialization.DescriptorSerializer;
064    import org.jetbrains.kotlin.serialization.ProtoBuf;
065    import org.jetbrains.kotlin.serialization.jvm.BitEncoding;
066    import org.jetbrains.kotlin.types.JetType;
067    import org.jetbrains.kotlin.types.checker.JetTypeChecker;
068    import org.jetbrains.org.objectweb.asm.*;
069    import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
070    import org.jetbrains.org.objectweb.asm.commons.Method;
071    
072    import java.util.*;
073    
074    import static kotlin.KotlinPackage.firstOrNull;
075    import static org.jetbrains.kotlin.codegen.AsmUtil.*;
076    import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
077    import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.enumEntryNeedSubclass;
078    import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
079    import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
080    import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getSecondaryConstructors;
081    import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
082    import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.*;
083    import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
084    import static org.jetbrains.kotlin.serialization.NameSerializationUtil.createNameResolver;
085    import static org.jetbrains.kotlin.types.Variance.INVARIANT;
086    import static org.jetbrains.org.objectweb.asm.Opcodes.*;
087    
088    public class ImplementationBodyCodegen extends ClassBodyCodegen {
089        private static final String ENUM_VALUES_FIELD_NAME = "$VALUES";
090        private Type superClassAsmType;
091        @Nullable // null means java/lang/Object
092        private JetType superClassType;
093        private final Type classAsmType;
094    
095        private List<PropertyAndDefaultValue> companionObjectPropertiesToCopy;
096    
097        private final List<Function2<ImplementationBodyCodegen, ClassBuilder, Unit>> additionalTasks =
098                new ArrayList<Function2<ImplementationBodyCodegen, ClassBuilder, Unit>>();
099    
100        public ImplementationBodyCodegen(
101                @NotNull JetClassOrObject aClass,
102                @NotNull ClassContext context,
103                @NotNull ClassBuilder v,
104                @NotNull GenerationState state,
105                @Nullable MemberCodegen<?> parentCodegen
106        ) {
107            super(aClass, context, v, state, parentCodegen);
108            this.classAsmType = typeMapper.mapClass(descriptor);
109        }
110    
111        @Override
112        protected void generateDeclaration() {
113            getSuperClass();
114    
115            JvmClassSignature signature = signature();
116    
117            boolean isAbstract = false;
118            boolean isInterface = false;
119            boolean isFinal = false;
120            boolean isStatic;
121            boolean isAnnotation = false;
122            boolean isEnum = false;
123    
124            if (myClass instanceof JetClass) {
125                JetClass jetClass = (JetClass) myClass;
126                if (jetClass.hasModifier(JetTokens.ABSTRACT_KEYWORD)) {
127                    isAbstract = true;
128                }
129                if (jetClass.isTrait()) {
130                    isAbstract = true;
131                    isInterface = true;
132                }
133                else if (jetClass.isAnnotation()) {
134                    isAbstract = true;
135                    isInterface = true;
136                    isAnnotation = true;
137                    signature.getInterfaces().add("java/lang/annotation/Annotation");
138                }
139                else if (jetClass.isEnum()) {
140                    isAbstract = hasAbstractMembers(descriptor);
141                    isEnum = true;
142                }
143    
144                if (isObject(descriptor)) {
145                    isFinal = true;
146                }
147    
148                if (!jetClass.hasModifier(JetTokens.OPEN_KEYWORD) && !isAbstract) {
149                    // Light-class mode: Do not make enum classes final since PsiClass corresponding to enum is expected to be inheritable from
150                    isFinal = !(jetClass.isEnum() && state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES);
151                }
152                isStatic = !jetClass.isInner();
153            }
154            else {
155                isStatic = myClass instanceof JetObjectDeclaration && ((JetObjectDeclaration) myClass).isCompanion() ;
156                isFinal = true;
157            }
158    
159            int access = 0;
160    
161            if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES && !DescriptorUtils.isTopLevelDeclaration(descriptor)) {
162                // ClassBuilderMode.LIGHT_CLASSES means we are generating light classes & looking at a nested or inner class
163                // Light class generation is implemented so that Cls-classes only read bare code of classes,
164                // without knowing whether these classes are inner or not (see ClassStubBuilder.EMPTY_STRATEGY)
165                // Thus we must write full accessibility flags on inner classes in this mode
166                access |= getVisibilityAccessFlag(descriptor);
167                // Same for STATIC
168                if (isStatic) {
169                    access |= ACC_STATIC;
170                }
171            }
172            else {
173                access |= getVisibilityAccessFlagForClass(descriptor);
174            }
175            if (isAbstract) {
176                access |= ACC_ABSTRACT;
177            }
178            if (isInterface) {
179                access |= ACC_INTERFACE; // ACC_SUPER
180            }
181            else {
182                access |= ACC_SUPER;
183            }
184            if (isFinal) {
185                access |= ACC_FINAL;
186            }
187            if (isAnnotation) {
188                access |= ACC_ANNOTATION;
189            }
190            if (KotlinBuiltIns.isDeprecated(descriptor)) {
191                access |= ACC_DEPRECATED;
192            }
193            if (isEnum) {
194                for (JetDeclaration declaration : myClass.getDeclarations()) {
195                    if (declaration instanceof JetEnumEntry) {
196                        if (enumEntryNeedSubclass(bindingContext, (JetEnumEntry) declaration)) {
197                            access &= ~ACC_FINAL;
198                        }
199                    }
200                }
201                access |= ACC_ENUM;
202            }
203            List<String> interfaces = signature.getInterfaces();
204            v.defineClass(myClass, V1_6,
205                          access,
206                          signature.getName(),
207                          signature.getJavaGenericSignature(),
208                          signature.getSuperclassName(),
209                          ArrayUtil.toStringArray(interfaces)
210            );
211            v.visitSource(myClass.getContainingFile().getName(), null);
212    
213            InlineCodegenUtil.initDefaultSourceMappingIfNeeded(context, this, state);
214    
215            writeEnclosingMethod();
216    
217            AnnotationCodegen.forClass(v.getVisitor(), typeMapper).genAnnotations(descriptor, null);
218    
219            generateReflectionObjectFieldIfNeeded();
220        }
221    
222        @Override
223        protected void generateKotlinAnnotation() {
224            if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
225    
226            KotlinClass.Kind kind;
227            if (isAnonymousObject(descriptor)) {
228                kind = KotlinClass.Kind.ANONYMOUS_OBJECT;
229            }
230            else if (isTopLevelOrInnerClass(descriptor)) {
231                kind = KotlinClass.Kind.CLASS;
232            }
233            else {
234                // LOCAL_CLASS is also written to inner classes of local classes
235                kind = KotlinClass.Kind.LOCAL_CLASS;
236            }
237    
238            DescriptorSerializer serializer =
239                    DescriptorSerializer.create(descriptor, new JvmSerializerExtension(v.getSerializationBindings(), typeMapper));
240    
241            ProtoBuf.Class classProto = serializer.classProto(descriptor).build();
242    
243            ClassData data = new ClassData(createNameResolver(serializer.getStringTable()), 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(data.toBytes())) {
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            codegen.gen(constructor.getBodyExpression(), Type.VOID_TYPE);
1180    
1181            iv.visitInsn(RETURN);
1182        }
1183    
1184        private void generateInitializers(@NotNull final ExpressionCodegen codegen) {
1185            generateInitializers(new Function0<ExpressionCodegen>() {
1186                @Override
1187                public ExpressionCodegen invoke() {
1188                    return codegen;
1189                }
1190            });
1191        }
1192    
1193        private void generateClosureInitialization(@NotNull InstructionAdapter iv) {
1194            MutableClosure closure = context.closure;
1195            if (closure != null) {
1196                List<FieldInfo> argsFromClosure = ClosureCodegen.calculateConstructorParameters(typeMapper, closure, classAsmType);
1197                int k = 1;
1198                for (FieldInfo info : argsFromClosure) {
1199                    k = AsmUtil.genAssignInstanceFieldFromParam(info, k, iv);
1200                }
1201            }
1202        }
1203    
1204        private void genSimpleSuperCall(InstructionAdapter iv) {
1205            iv.load(0, superClassAsmType);
1206            if (descriptor.getKind() == ClassKind.ENUM_CLASS || descriptor.getKind() == ClassKind.ENUM_ENTRY) {
1207                iv.load(1, JAVA_STRING_TYPE);
1208                iv.load(2, Type.INT_TYPE);
1209                iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "(Ljava/lang/String;I)V", false);
1210            }
1211            else {
1212                iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "()V", false);
1213            }
1214        }
1215    
1216        private class DelegationFieldsInfo {
1217            private class Field {
1218                public final Type type;
1219                public final String name;
1220                public final boolean generateField;
1221    
1222                private Field(Type type, String name, boolean generateField) {
1223                    this.type = type;
1224                    this.name = name;
1225                    this.generateField = generateField;
1226                }
1227    
1228                @NotNull
1229                public StackValue getStackValue() {
1230                    return StackValue.field(type, classAsmType, name, false, StackValue.none());
1231                }
1232            }
1233            private final Map<JetDelegatorByExpressionSpecifier, Field> fields = new HashMap<JetDelegatorByExpressionSpecifier, Field>();
1234    
1235            @NotNull
1236            public Field getInfo(JetDelegatorByExpressionSpecifier specifier) {
1237                return fields.get(specifier);
1238            }
1239    
1240            private void addField(JetDelegatorByExpressionSpecifier specifier, PropertyDescriptor propertyDescriptor) {
1241                fields.put(specifier,
1242                           new Field(typeMapper.mapType(propertyDescriptor), propertyDescriptor.getName().asString(), false));
1243            }
1244    
1245            private void addField(JetDelegatorByExpressionSpecifier specifier, Type type, String name) {
1246                fields.put(specifier, new Field(type, name, true));
1247            }
1248        }
1249    
1250        @NotNull
1251        private DelegationFieldsInfo getDelegationFieldsInfo(@NotNull List<JetDelegationSpecifier> delegationSpecifiers) {
1252            DelegationFieldsInfo result = new DelegationFieldsInfo();
1253            int n = 0;
1254            for (JetDelegationSpecifier specifier : delegationSpecifiers) {
1255                if (specifier instanceof JetDelegatorByExpressionSpecifier) {
1256                    JetExpression expression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression();
1257                    PropertyDescriptor propertyDescriptor = CodegenUtil.getDelegatePropertyIfAny(expression, descriptor, bindingContext);
1258    
1259    
1260                    if (CodegenUtil.isFinalPropertyWithBackingField(propertyDescriptor, bindingContext)) {
1261                        result.addField((JetDelegatorByExpressionSpecifier) specifier, propertyDescriptor);
1262                    }
1263                    else {
1264                        JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression);
1265                        Type asmType =
1266                                expressionType != null ? typeMapper.mapType(expressionType) : typeMapper.mapType(getSuperClass(specifier));
1267                        result.addField((JetDelegatorByExpressionSpecifier) specifier, asmType, "$delegate_" + n);
1268                    }
1269                    n++;
1270                }
1271            }
1272            return result;
1273        }
1274    
1275        @NotNull
1276        private ClassDescriptor getSuperClass(@NotNull JetDelegationSpecifier specifier) {
1277            return CodegenUtil.getSuperClassByDelegationSpecifier(specifier, bindingContext);
1278        }
1279    
1280        private void genCallToDelegatorByExpressionSpecifier(
1281                InstructionAdapter iv,
1282                ExpressionCodegen codegen,
1283                JetDelegatorByExpressionSpecifier specifier,
1284                DelegationFieldsInfo fieldsInfo
1285        ) {
1286            JetExpression expression = specifier.getDelegateExpression();
1287    
1288            DelegationFieldsInfo.Field fieldInfo = fieldsInfo.getInfo(specifier);
1289            if (fieldInfo.generateField) {
1290                iv.load(0, classAsmType);
1291                fieldInfo.getStackValue().store(codegen.gen(expression), iv);
1292            }
1293        }
1294    
1295        private void lookupConstructorExpressionsInClosureIfPresent() {
1296            if (state.getClassBuilderMode() != ClassBuilderMode.FULL || descriptor.getConstructors().isEmpty()) return;
1297    
1298            JetVisitorVoid visitor = new JetVisitorVoid() {
1299                @Override
1300                public void visitJetElement(@NotNull JetElement e) {
1301                    e.acceptChildren(this);
1302                }
1303    
1304                @Override
1305                public void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expr) {
1306                    DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expr);
1307    
1308                    DeclarationDescriptor toLookup;
1309                    if (isLocalFunction(descriptor)) {
1310                        toLookup = descriptor;
1311                    }
1312                    else if (descriptor instanceof CallableMemberDescriptor) {
1313                        toLookup = descriptor.getContainingDeclaration();
1314                    }
1315                    else if (descriptor instanceof VariableDescriptor) {
1316                        if (descriptor.getContainingDeclaration() instanceof ConstructorDescriptor) {
1317                            ClassDescriptor classDescriptor =
1318                                    (ClassDescriptor) descriptor.getContainingDeclaration().getContainingDeclaration();
1319                            if (classDescriptor == ImplementationBodyCodegen.this.descriptor) return;
1320                        }
1321                        toLookup = descriptor;
1322                    }
1323                    else return;
1324    
1325                    context.lookupInContext(toLookup, StackValue.LOCAL_0, state, true);
1326                }
1327    
1328                @Override
1329                public void visitThisExpression(@NotNull JetThisExpression expression) {
1330                    DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference());
1331                    assert descriptor instanceof CallableDescriptor ||
1332                           descriptor instanceof ClassDescriptor : "'This' reference target should be class or callable descriptor but was " + descriptor;
1333                    if (descriptor instanceof ClassDescriptor) {
1334                        context.lookupInContext(descriptor, StackValue.LOCAL_0, state, true);
1335                    }
1336    
1337                    if (descriptor instanceof CallableDescriptor) {
1338                        ReceiverParameterDescriptor parameter = ((CallableDescriptor) descriptor).getExtensionReceiverParameter();
1339                        if (parameter != null) {
1340                            context.lookupInContext(parameter, StackValue.LOCAL_0, state, true);
1341                        }
1342                    }
1343                }
1344            };
1345    
1346            for (JetDeclaration declaration : myClass.getDeclarations()) {
1347                if (declaration instanceof JetProperty) {
1348                    JetProperty property = (JetProperty) declaration;
1349                    JetExpression initializer = property.getInitializer();
1350                    if (initializer != null) {
1351                        initializer.accept(visitor);
1352                    }
1353                }
1354                else if (declaration instanceof JetClassInitializer) {
1355                    JetClassInitializer initializer = (JetClassInitializer) declaration;
1356                    initializer.accept(visitor);
1357                }
1358                else if (declaration instanceof JetSecondaryConstructor) {
1359                    JetSecondaryConstructor constructor = (JetSecondaryConstructor) declaration;
1360                    constructor.accept(visitor);
1361                }
1362            }
1363    
1364            for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) {
1365                if (specifier instanceof JetDelegatorByExpressionSpecifier) {
1366                    JetExpression delegateExpression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression();
1367                    assert delegateExpression != null;
1368                    delegateExpression.accept(visitor);
1369                }
1370            }
1371    
1372            ClassDescriptor superClass = DescriptorUtilPackage.getSuperClassNotAny(descriptor);
1373            if (superClass != null) {
1374                if (superClass.isInner()) {
1375                    context.lookupInContext(superClass.getContainingDeclaration(), StackValue.LOCAL_0, state, true);
1376                }
1377    
1378                ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor();
1379                if (primaryConstructor != null && !isAnonymousObject(descriptor)) {
1380                    ResolvedCall<ConstructorDescriptor> delegationCall = getDelegationConstructorCall(bindingContext, primaryConstructor);
1381                    JetValueArgumentList argumentList = delegationCall != null ? delegationCall.getCall().getValueArgumentList() : null;
1382                    if (argumentList != null) {
1383                        argumentList.accept(visitor);
1384                    }
1385                }
1386            }
1387        }
1388    
1389        private boolean ignoreIfTraitOrAnnotation() {
1390            if (myClass instanceof JetClass) {
1391                JetClass aClass = (JetClass) myClass;
1392                if (aClass.isTrait()) {
1393                    return true;
1394                }
1395                if (aClass.isAnnotation()) {
1396                    return true;
1397                }
1398            }
1399            return false;
1400        }
1401    
1402        private void generateTraitMethods() {
1403            if (JetPsiUtil.isTrait(myClass)) return;
1404    
1405            for (Map.Entry<FunctionDescriptor, FunctionDescriptor> entry : CodegenUtil.getTraitMethods(descriptor).entrySet()) {
1406                FunctionDescriptor traitFun = entry.getKey();
1407                //skip java 8 default methods
1408                if (!(traitFun instanceof JavaCallableMemberDescriptor)) {
1409                    generateDelegationToTraitImpl(traitFun, entry.getValue());
1410                }
1411            }
1412        }
1413    
1414        private void generateDelegationToTraitImpl(@NotNull final FunctionDescriptor traitFun, @NotNull FunctionDescriptor inheritedFun) {
1415            functionCodegen.generateMethod(
1416                    DelegationToTraitImpl(descriptorToDeclaration(traitFun), traitFun),
1417                    inheritedFun,
1418                    new FunctionGenerationStrategy.CodegenBased<FunctionDescriptor>(state, inheritedFun) {
1419                        @Override
1420                        public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
1421                            DeclarationDescriptor containingDeclaration = traitFun.getContainingDeclaration();
1422                            if (!DescriptorUtils.isTrait(containingDeclaration)) return;
1423                            ClassDescriptor containingTrait = (ClassDescriptor) containingDeclaration;
1424                            Type traitImplType = typeMapper.mapTraitImpl(containingTrait);
1425    
1426                            Method traitMethod = typeMapper.mapSignature(traitFun.getOriginal(), OwnerKind.TRAIT_IMPL).getAsmMethod();
1427    
1428                            Type[] argTypes = signature.getAsmMethod().getArgumentTypes();
1429                            Type[] originalArgTypes = traitMethod.getArgumentTypes();
1430                            assert originalArgTypes.length == argTypes.length + 1 :
1431                                    "Invalid trait implementation signature: " + signature + " vs " + traitMethod + " for " + traitFun;
1432    
1433                            InstructionAdapter iv = codegen.v;
1434                            iv.load(0, OBJECT_TYPE);
1435                            for (int i = 0, reg = 1; i < argTypes.length; i++) {
1436                                StackValue.local(reg, argTypes[i]).put(originalArgTypes[i + 1], iv);
1437                                //noinspection AssignmentToForLoopParameter
1438                                reg += argTypes[i].getSize();
1439                            }
1440    
1441                            if (KotlinBuiltIns.getInstance().isCloneable(containingTrait) && traitMethod.getName().equals("clone")) {
1442                                // A special hack for Cloneable: there's no kotlin/Cloneable$$TImpl class at runtime,
1443                                // and its 'clone' method is actually located in java/lang/Object
1444                                iv.invokespecial("java/lang/Object", "clone", "()Ljava/lang/Object;", false);
1445                            }
1446                            else {
1447                                iv.invokestatic(traitImplType.getInternalName(), traitMethod.getName(), traitMethod.getDescriptor(), false);
1448                            }
1449    
1450                            Type returnType = signature.getReturnType();
1451                            StackValue.onStack(traitMethod.getReturnType()).put(returnType, iv);
1452                            iv.areturn(returnType);
1453                        }
1454                    }
1455            );
1456        }
1457    
1458        private void generateDelegatorToConstructorCall(
1459                @NotNull InstructionAdapter iv,
1460                @NotNull ExpressionCodegen codegen,
1461                @NotNull ConstructorDescriptor constructorDescriptor,
1462                @Nullable ResolvedCall<ConstructorDescriptor> delegationConstructorCall
1463        ) {
1464            if (delegationConstructorCall == null) {
1465                genSimpleSuperCall(iv);
1466                return;
1467            }
1468            iv.load(0, OBJECT_TYPE);
1469            ConstructorDescriptor delegateConstructor = delegationConstructorCall.getResultingDescriptor();
1470    
1471            CallableMethod delegateConstructorCallable = typeMapper.mapToCallableMethod(delegateConstructor);
1472            CallableMethod callable = typeMapper.mapToCallableMethod(constructorDescriptor);
1473    
1474            List<JvmMethodParameterSignature> delegatingParameters = delegateConstructorCallable.getValueParameters();
1475            List<JvmMethodParameterSignature> parameters = callable.getValueParameters();
1476    
1477            ArgumentGenerator argumentGenerator;
1478            if (isSameClassConstructor(delegateConstructor)) {
1479                // if it's the same class constructor we should just pass all synthetic parameters
1480                argumentGenerator =
1481                        generateThisCallImplicitArguments(iv, codegen, delegateConstructor, delegateConstructorCallable, delegatingParameters,
1482                                                          parameters);
1483            }
1484            else {
1485                argumentGenerator =
1486                        generateSuperCallImplicitArguments(iv, codegen, constructorDescriptor, delegateConstructor, delegateConstructorCallable,
1487                                                           delegatingParameters,
1488                                                           parameters);
1489            }
1490    
1491            codegen.invokeMethodWithArguments(
1492                    delegateConstructorCallable, delegationConstructorCall, StackValue.none(), codegen.defaultCallGenerator, argumentGenerator);
1493        }
1494    
1495        private boolean isSameClassConstructor(@Nullable ConstructorDescriptor delegatingConstructor) {
1496            return delegatingConstructor != null && delegatingConstructor.getContainingDeclaration() == descriptor;
1497        }
1498    
1499        @NotNull
1500        private ArgumentGenerator generateSuperCallImplicitArguments(
1501                @NotNull InstructionAdapter iv,
1502                @NotNull ExpressionCodegen codegen,
1503                @NotNull ConstructorDescriptor constructorDescriptor,
1504                @NotNull ConstructorDescriptor superConstructor,
1505                @NotNull CallableMethod superCallable,
1506                @NotNull List<JvmMethodParameterSignature> superParameters,
1507                @NotNull List<JvmMethodParameterSignature> parameters
1508        ) {
1509            int offset = 1;
1510            int superIndex = 0;
1511    
1512            // Here we match all the super constructor parameters except those with kind VALUE to the derived constructor parameters, push
1513            // them all onto the stack and update "offset" variable so that in the end it points to the slot of the first VALUE argument
1514            for (JvmMethodParameterSignature parameter : parameters) {
1515                if (superIndex >= superParameters.size()) break;
1516    
1517                JvmMethodParameterKind superKind = superParameters.get(superIndex).getKind();
1518                JvmMethodParameterKind kind = parameter.getKind();
1519                Type type = parameter.getAsmType();
1520    
1521                if (superKind == JvmMethodParameterKind.VALUE && kind == JvmMethodParameterKind.SUPER_CALL_PARAM) {
1522                    // Stop when we reach the actual value parameters present in the code; they will be generated via ResolvedCall below
1523                    break;
1524                }
1525    
1526                if (superKind == JvmMethodParameterKind.OUTER) {
1527                    assert kind == JvmMethodParameterKind.OUTER || kind == JvmMethodParameterKind.SUPER_CALL_PARAM :
1528                            String.format("Non-outer parameter incorrectly mapped to outer for %s: %s vs %s",
1529                                          constructorDescriptor, parameters, superParameters);
1530                    // Super constructor requires OUTER parameter, but our OUTER instance may be different from what is expected by the super
1531                    // constructor. We need to traverse our outer classes from the bottom up, to find the needed class
1532                    // TODO: isSuper should be "true" but this makes some tests on inner classes extending outer fail
1533                    // See innerExtendsOuter.kt, semantics of inner classes extending their outer should be changed to be as in Java
1534                    ClassDescriptor outerForSuper = (ClassDescriptor) superConstructor.getContainingDeclaration().getContainingDeclaration();
1535                    StackValue outer = codegen.generateThisOrOuter(outerForSuper, false);
1536                    outer.put(outer.type, codegen.v);
1537                    superIndex++;
1538                }
1539                else if (kind == JvmMethodParameterKind.SUPER_CALL_PARAM || kind == JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL) {
1540                    iv.load(offset, type);
1541                    superIndex++;
1542                }
1543    
1544                offset += type.getSize();
1545            }
1546    
1547            if (isAnonymousObject(descriptor)) {
1548                List<JvmMethodParameterSignature> superValues = superParameters.subList(superIndex, superParameters.size());
1549                return new ObjectSuperCallArgumentGenerator(superValues, iv, offset);
1550            }
1551            else {
1552                return new CallBasedArgumentGenerator(codegen, codegen.defaultCallGenerator, superConstructor.getValueParameters(),
1553                                                       superCallable.getValueParameterTypes());
1554            }
1555        }
1556    
1557        @NotNull
1558        private static ArgumentGenerator generateThisCallImplicitArguments(
1559                @NotNull InstructionAdapter iv,
1560                @NotNull ExpressionCodegen codegen,
1561                @NotNull ConstructorDescriptor delegatingConstructor,
1562                @NotNull CallableMethod delegatingCallable,
1563                @NotNull List<JvmMethodParameterSignature> delegatingParameters,
1564                @NotNull List<JvmMethodParameterSignature> parameters
1565        ) {
1566            int offset = 1;
1567            int index = 0;
1568            for (; index < delegatingParameters.size(); index++) {
1569                JvmMethodParameterKind delegatingKind = delegatingParameters.get(index).getKind();
1570                if (delegatingKind == JvmMethodParameterKind.VALUE) {
1571                    assert index == parameters.size() || parameters.get(index).getKind() == JvmMethodParameterKind.VALUE:
1572                            "Delegating constructor has not enough implicit parameters";
1573                    break;
1574                }
1575                assert index < parameters.size() && parameters.get(index).getKind() == delegatingKind :
1576                        "Constructors of the same class should have the same set of implicit arguments";
1577                JvmMethodParameterSignature parameter = parameters.get(index);
1578    
1579                iv.load(offset, parameter.getAsmType());
1580                offset += parameter.getAsmType().getSize();
1581            }
1582    
1583            assert index == parameters.size() || parameters.get(index).getKind() == JvmMethodParameterKind.VALUE :
1584                        "Delegating constructor has not enough parameters";
1585    
1586            return new CallBasedArgumentGenerator(codegen, codegen.defaultCallGenerator, delegatingConstructor.getValueParameters(),
1587                                                  delegatingCallable.getValueParameterTypes());
1588        }
1589    
1590        private static class ObjectSuperCallArgumentGenerator extends ArgumentGenerator {
1591            private final List<JvmMethodParameterSignature> parameters;
1592            private final InstructionAdapter iv;
1593            private int offset;
1594    
1595            public ObjectSuperCallArgumentGenerator(
1596                    @NotNull List<JvmMethodParameterSignature> superParameters,
1597                    @NotNull InstructionAdapter iv,
1598                    int firstValueParamOffset
1599            ) {
1600                this.parameters = superParameters;
1601                this.iv = iv;
1602                this.offset = firstValueParamOffset;
1603            }
1604    
1605            @Override
1606            public void generateExpression(int i, @NotNull ExpressionValueArgument argument) {
1607                generateSuperCallArgument(i);
1608            }
1609    
1610            @Override
1611            public void generateDefault(int i, @NotNull DefaultValueArgument argument) {
1612                pushDefaultValueOnStack(parameters.get(i).getAsmType(), iv);
1613            }
1614    
1615            @Override
1616            public void generateVararg(int i, @NotNull VarargValueArgument argument) {
1617                generateSuperCallArgument(i);
1618            }
1619    
1620            private void generateSuperCallArgument(int i) {
1621                Type type = parameters.get(i).getAsmType();
1622                iv.load(offset, type);
1623                offset += type.getSize();
1624            }
1625        }
1626    
1627        @Override
1628        protected void generateDeclaration(JetDeclaration declaration) {
1629            if (declaration instanceof JetEnumEntry) {
1630                String name = declaration.getName();
1631                assert name != null : "Enum entry has no name: " + declaration.getText();
1632                ClassDescriptor entryDescriptor = bindingContext.get(BindingContext.CLASS, declaration);
1633                FieldVisitor fv = v.newField(OtherOrigin(declaration, entryDescriptor), ACC_PUBLIC | ACC_ENUM | ACC_STATIC | ACC_FINAL,
1634                                             name, classAsmType.getDescriptor(), null, null);
1635                AnnotationCodegen.forField(fv, typeMapper).genAnnotations(entryDescriptor, null);
1636                myEnumConstants.add((JetEnumEntry) declaration);
1637            }
1638    
1639            super.generateDeclaration(declaration);
1640        }
1641    
1642        private final List<JetEnumEntry> myEnumConstants = new ArrayList<JetEnumEntry>();
1643    
1644        private void initializeEnumConstants() {
1645            if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
1646    
1647            ExpressionCodegen codegen = createOrGetClInitCodegen();
1648            InstructionAdapter iv = codegen.v;
1649    
1650            Type arrayAsmType = typeMapper.mapType(KotlinBuiltIns.getInstance().getArrayType(INVARIANT, descriptor.getDefaultType()));
1651            v.newField(OtherOrigin(myClass), ACC_PRIVATE | ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, ENUM_VALUES_FIELD_NAME,
1652                       arrayAsmType.getDescriptor(), null, null);
1653    
1654            iv.iconst(myEnumConstants.size());
1655            iv.newarray(classAsmType);
1656    
1657            if (!myEnumConstants.isEmpty()) {
1658                iv.dup();
1659                for (int ordinal = 0, size = myEnumConstants.size(); ordinal < size; ordinal++) {
1660                    initializeEnumConstant(codegen, ordinal);
1661                }
1662            }
1663    
1664            iv.putstatic(classAsmType.getInternalName(), ENUM_VALUES_FIELD_NAME, arrayAsmType.getDescriptor());
1665        }
1666    
1667        private void initializeEnumConstant(@NotNull ExpressionCodegen codegen, int ordinal) {
1668            InstructionAdapter iv = codegen.v;
1669            JetEnumEntry enumConstant = myEnumConstants.get(ordinal);
1670    
1671            iv.dup();
1672            iv.iconst(ordinal);
1673    
1674            ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, enumConstant);
1675            assert classDescriptor != null;
1676            Type implClass = typeMapper.mapClass(classDescriptor);
1677    
1678            List<JetDelegationSpecifier> delegationSpecifiers = enumConstant.getDelegationSpecifiers();
1679            if (delegationSpecifiers.size() > 1) {
1680                throw new UnsupportedOperationException("multiple delegation specifiers for enum constant not supported");
1681            }
1682    
1683            iv.anew(implClass);
1684            iv.dup();
1685    
1686            iv.aconst(enumConstant.getName());
1687            iv.iconst(ordinal);
1688    
1689            if (delegationSpecifiers.size() == 1 && !enumEntryNeedSubclass(bindingContext, enumConstant)) {
1690                JetDelegationSpecifier specifier = delegationSpecifiers.get(0);
1691                if (!(specifier instanceof JetDelegatorToSuperCall)) {
1692                    throw new UnsupportedOperationException("unsupported type of enum constant initializer: " + specifier);
1693                }
1694    
1695                ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCallWithAssert(specifier, bindingContext);
1696    
1697                CallableMethod method = typeMapper.mapToCallableMethod((ConstructorDescriptor) resolvedCall.getResultingDescriptor());
1698    
1699                codegen.invokeMethodWithArguments(method, resolvedCall, StackValue.none());
1700            }
1701            else {
1702                iv.invokespecial(implClass.getInternalName(), "<init>", "(Ljava/lang/String;I)V", false);
1703            }
1704    
1705            iv.dup();
1706            iv.putstatic(classAsmType.getInternalName(), enumConstant.getName(), classAsmType.getDescriptor());
1707            iv.astore(OBJECT_TYPE);
1708        }
1709    
1710        private void generateDelegates(DelegationFieldsInfo delegationFieldsInfo) {
1711            for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) {
1712                if (specifier instanceof JetDelegatorByExpressionSpecifier) {
1713                    DelegationFieldsInfo.Field field = delegationFieldsInfo.getInfo((JetDelegatorByExpressionSpecifier) specifier);
1714                    generateDelegateField(field);
1715                    JetExpression delegateExpression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression();
1716                    JetType delegateExpressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, delegateExpression);
1717                    generateDelegates(getSuperClass(specifier), delegateExpressionType, field);
1718                }
1719            }
1720        }
1721    
1722        private void generateDelegateField(DelegationFieldsInfo.Field fieldInfo) {
1723            if (!fieldInfo.generateField) return;
1724    
1725            v.newField(JvmDeclarationOrigin.NO_ORIGIN, ACC_PRIVATE | ACC_FINAL | ACC_SYNTHETIC,
1726                       fieldInfo.name, fieldInfo.type.getDescriptor(), /*TODO*/null, null);
1727        }
1728    
1729        protected void generateDelegates(ClassDescriptor toTrait, JetType delegateExpressionType, DelegationFieldsInfo.Field field) {
1730            for (Map.Entry<CallableMemberDescriptor, CallableDescriptor> entry : CodegenUtilKt.getDelegates(descriptor, toTrait, delegateExpressionType).entrySet()) {
1731                CallableMemberDescriptor callableMemberDescriptor = entry.getKey();
1732                CallableDescriptor delegateTo = entry.getValue();
1733                if (callableMemberDescriptor instanceof PropertyDescriptor) {
1734                    propertyCodegen
1735                            .genDelegate((PropertyDescriptor) callableMemberDescriptor, (PropertyDescriptor) delegateTo, field.getStackValue());
1736                }
1737                else if (callableMemberDescriptor instanceof FunctionDescriptor) {
1738                    functionCodegen
1739                            .genDelegate((FunctionDescriptor) callableMemberDescriptor, (FunctionDescriptor) delegateTo, field.getStackValue());
1740                }
1741            }
1742        }
1743    
1744        public void addCompanionObjectPropertyToCopy(@NotNull PropertyDescriptor descriptor, Object defaultValue) {
1745            if (companionObjectPropertiesToCopy == null) {
1746                companionObjectPropertiesToCopy = new ArrayList<PropertyAndDefaultValue>();
1747            }
1748            companionObjectPropertiesToCopy.add(new PropertyAndDefaultValue(descriptor, defaultValue));
1749        }
1750    
1751        @Override
1752        protected void done() {
1753            for (Function2<ImplementationBodyCodegen, ClassBuilder, Unit> task : additionalTasks) {
1754                task.invoke(this, v);
1755            }
1756    
1757            super.done();
1758        }
1759    
1760        private static class PropertyAndDefaultValue {
1761            public final PropertyDescriptor descriptor;
1762            public final Object defaultValue;
1763    
1764            public PropertyAndDefaultValue(@NotNull PropertyDescriptor descriptor, Object defaultValue) {
1765                this.descriptor = descriptor;
1766                this.defaultValue = defaultValue;
1767            }
1768        }
1769    
1770        public void addAdditionalTask(Function2<ImplementationBodyCodegen, ClassBuilder, Unit> additionalTask) {
1771            additionalTasks.add(additionalTask);
1772        }
1773    }