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