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