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