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