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