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