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