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