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