001    /*
002     * Copyright 2010-2015 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.kotlin.codegen;
018    
019    import com.google.common.collect.ImmutableMap;
020    import com.google.common.collect.Sets;
021    import com.intellij.openapi.util.Pair;
022    import com.intellij.psi.tree.IElementType;
023    import kotlin.Unit;
024    import kotlin.jvm.functions.Function1;
025    import org.jetbrains.annotations.NotNull;
026    import org.jetbrains.annotations.Nullable;
027    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
028    import org.jetbrains.kotlin.builtins.PrimitiveType;
029    import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
030    import org.jetbrains.kotlin.codegen.context.CodegenContext;
031    import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods;
032    import org.jetbrains.kotlin.codegen.serialization.JvmStringTable;
033    import org.jetbrains.kotlin.codegen.state.GenerationState;
034    import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
035    import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl;
036    import org.jetbrains.kotlin.descriptors.*;
037    import org.jetbrains.kotlin.lexer.KtTokens;
038    import org.jetbrains.kotlin.load.java.JavaVisibilities;
039    import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
040    import org.jetbrains.kotlin.name.FqName;
041    import org.jetbrains.kotlin.protobuf.MessageLite;
042    import org.jetbrains.kotlin.renderer.DescriptorRenderer;
043    import org.jetbrains.kotlin.resolve.DeprecationUtilKt;
044    import org.jetbrains.kotlin.resolve.DescriptorUtils;
045    import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt;
046    import org.jetbrains.kotlin.resolve.inline.InlineUtil;
047    import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
048    import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType;
049    import org.jetbrains.kotlin.resolve.jvm.RuntimeAssertionInfo;
050    import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
051    import org.jetbrains.kotlin.serialization.DescriptorSerializer;
052    import org.jetbrains.kotlin.serialization.jvm.BitEncoding;
053    import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor;
054    import org.jetbrains.kotlin.types.KotlinType;
055    import org.jetbrains.org.objectweb.asm.*;
056    import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
057    import org.jetbrains.org.objectweb.asm.commons.Method;
058    
059    import java.util.ArrayList;
060    import java.util.List;
061    import java.util.Map;
062    import java.util.Set;
063    
064    import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isBoolean;
065    import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isPrimitiveClass;
066    import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConstOrHasJvmFieldAnnotation;
067    import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface;
068    import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUtilKt.isInlineOnlyOrReified;
069    import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
070    import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
071    import static org.jetbrains.kotlin.types.TypeUtils.isNullableType;
072    import static org.jetbrains.org.objectweb.asm.Opcodes.*;
073    
074    public class AsmUtil {
075        private static final Set<Type> STRING_BUILDER_OBJECT_APPEND_ARG_TYPES = Sets.newHashSet(
076                getType(String.class),
077                getType(StringBuffer.class),
078                getType(CharSequence.class)
079        );
080    
081        private static final int NO_FLAG_LOCAL = 0;
082        public static final int NO_FLAG_PACKAGE_PRIVATE = 0;
083    
084        @NotNull
085        private static final Map<Visibility, Integer> visibilityToAccessFlag = ImmutableMap.<Visibility, Integer>builder()
086                .put(Visibilities.PRIVATE, ACC_PRIVATE)
087                .put(Visibilities.PRIVATE_TO_THIS, ACC_PRIVATE)
088                .put(Visibilities.PROTECTED, ACC_PROTECTED)
089                .put(JavaVisibilities.PROTECTED_STATIC_VISIBILITY, ACC_PROTECTED)
090                .put(JavaVisibilities.PROTECTED_AND_PACKAGE, ACC_PROTECTED)
091                .put(Visibilities.PUBLIC, ACC_PUBLIC)
092                .put(Visibilities.INTERNAL, ACC_PUBLIC)
093                .put(Visibilities.LOCAL, NO_FLAG_LOCAL)
094                .put(JavaVisibilities.PACKAGE_VISIBILITY, NO_FLAG_PACKAGE_PRIVATE)
095                .build();
096    
097        public static final String CAPTURED_RECEIVER_FIELD = "receiver$0";
098        public static final String CAPTURED_THIS_FIELD = "this$0";
099    
100        private static final ImmutableMap<Integer, JvmPrimitiveType> primitiveTypeByAsmSort;
101        private static final ImmutableMap<Type, Type> primitiveTypeByBoxedType;
102    
103        static {
104            ImmutableMap.Builder<Integer, JvmPrimitiveType> typeBySortBuilder = ImmutableMap.builder();
105            ImmutableMap.Builder<Type, Type> typeByWrapperBuilder = ImmutableMap.builder();
106            for (JvmPrimitiveType primitiveType : JvmPrimitiveType.values()) {
107                Type asmType = Type.getType(primitiveType.getDesc());
108                typeBySortBuilder.put(asmType.getSort(), primitiveType);
109                typeByWrapperBuilder.put(asmTypeByFqNameWithoutInnerClasses(primitiveType.getWrapperFqName()), asmType);
110            }
111            primitiveTypeByAsmSort = typeBySortBuilder.build();
112            primitiveTypeByBoxedType = typeByWrapperBuilder.build();
113        }
114    
115        private AsmUtil() {
116        }
117    
118        @NotNull
119        public static Type boxType(@NotNull Type type) {
120            JvmPrimitiveType jvmPrimitiveType = primitiveTypeByAsmSort.get(type.getSort());
121            return jvmPrimitiveType != null ? asmTypeByFqNameWithoutInnerClasses(jvmPrimitiveType.getWrapperFqName()) : type;
122        }
123    
124        @NotNull
125        public static Type unboxType(@NotNull Type boxedType) {
126            Type primitiveType = unboxPrimitiveTypeOrNull(boxedType);
127            if (primitiveType == null) {
128                throw new UnsupportedOperationException("Unboxing: " + boxedType);
129            }
130            return primitiveType;
131        }
132    
133        @Nullable
134        public static Type unboxPrimitiveTypeOrNull(@NotNull Type boxedType) {
135            return primitiveTypeByBoxedType.get(boxedType);
136        }
137    
138        public static boolean isIntPrimitive(Type type) {
139            return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE;
140        }
141    
142        public static boolean isNumberPrimitive(Type type) {
143            return isIntPrimitive(type) || type == Type.FLOAT_TYPE || type == Type.DOUBLE_TYPE || type == Type.LONG_TYPE;
144        }
145    
146        public static boolean isPrimitive(Type type) {
147            return type.getSort() != Type.OBJECT && type.getSort() != Type.ARRAY;
148        }
149    
150        public static boolean isPrimitiveNumberClassDescriptor(DeclarationDescriptor descriptor) {
151            if (!(descriptor instanceof ClassDescriptor)) {
152                return false;
153            }
154            return isPrimitiveClass((ClassDescriptor) descriptor) && !isBoolean((ClassDescriptor) descriptor);
155        }
156    
157        public static Type correctElementType(Type type) {
158            String internalName = type.getInternalName();
159            assert internalName.charAt(0) == '[';
160            return Type.getType(internalName.substring(1));
161        }
162    
163        @Nullable
164        public static PrimitiveType asmPrimitiveTypeToLangPrimitiveType(Type type) {
165            JvmPrimitiveType jvmPrimitiveType = primitiveTypeByAsmSort.get(type.getSort());
166            return jvmPrimitiveType != null ? jvmPrimitiveType.getPrimitiveType() : null;
167        }
168    
169        @NotNull
170        public static Method method(@NotNull String name, @NotNull Type returnType, @NotNull Type... parameterTypes) {
171            return new Method(name, Type.getMethodDescriptor(returnType, parameterTypes));
172        }
173    
174        public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) {
175            return (functionDescriptor.getModality() == Modality.ABSTRACT
176                    || isJvmInterface(functionDescriptor.getContainingDeclaration()))
177                   && !isStaticMethod(kind, functionDescriptor);
178        }
179    
180        public static boolean isStaticMethod(OwnerKind kind, CallableMemberDescriptor functionDescriptor) {
181            return isStaticKind(kind) ||
182                   KotlinTypeMapper.isStaticAccessor(functionDescriptor) ||
183                   CodegenUtilKt.isJvmStaticInObjectOrClass(functionDescriptor);
184        }
185    
186        public static boolean isStaticKind(OwnerKind kind) {
187            return kind == OwnerKind.PACKAGE || kind == OwnerKind.DEFAULT_IMPLS;
188        }
189    
190        public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind) {
191            int flags = getCommonCallableFlags(functionDescriptor);
192    
193            for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.METHOD_FLAGS) {
194                if (flagAnnotation.hasAnnotation(functionDescriptor.getOriginal())) {
195                    flags |= flagAnnotation.getJvmFlag();
196                }
197            }
198    
199            if (functionDescriptor.getOriginal().isExternal()) {
200                flags |= Opcodes.ACC_NATIVE;
201            }
202    
203            if (CodegenUtilKt.isJvmStaticInCompanionObject(functionDescriptor)) {
204                // Native method will be a member of the class, the companion object method will be delegated to it
205                flags &= ~Opcodes.ACC_NATIVE;
206            }
207    
208            if (functionDescriptor.getModality() == Modality.FINAL && !(functionDescriptor instanceof ConstructorDescriptor)) {
209                DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration();
210                if (!(containingDeclaration instanceof ClassDescriptor) ||
211                    ((ClassDescriptor) containingDeclaration).getKind() != ClassKind.INTERFACE) {
212                    flags |= ACC_FINAL;
213                }
214            }
215    
216            if (isStaticMethod(kind, functionDescriptor)) {
217                flags |= ACC_STATIC;
218            }
219    
220            if (isAbstractMethod(functionDescriptor, kind)) {
221                flags |= ACC_ABSTRACT;
222            }
223    
224            if (KotlinTypeMapper.isAccessor(functionDescriptor)
225                || AnnotationUtilKt.hasJvmSyntheticAnnotation(functionDescriptor)) {
226                flags |= ACC_SYNTHETIC;
227            }
228    
229            return flags;
230        }
231    
232        public static int getCommonCallableFlags(FunctionDescriptor functionDescriptor) {
233            int flags = getVisibilityAccessFlag(functionDescriptor);
234            flags |= getVarargsFlag(functionDescriptor);
235            flags |= getDeprecatedAccessFlag(functionDescriptor);
236            if (DeprecationUtilKt.isDeprecatedHidden(functionDescriptor, LanguageVersionSettingsImpl.DEFAULT)
237                || functionDescriptor instanceof PropertyAccessorDescriptor
238                   && DeprecationUtilKt.isDeprecatedHidden(
239                           ((PropertyAccessorDescriptor) functionDescriptor).getCorrespondingProperty(),
240                           LanguageVersionSettingsImpl.DEFAULT
241                   )
242            ) {
243                flags |= ACC_SYNTHETIC;
244            }
245            return flags;
246        }
247    
248        public static int getVisibilityAccessFlag(@NotNull MemberDescriptor descriptor) {
249            Integer specialCase = specialCaseVisibility(descriptor);
250            if (specialCase != null) {
251                return specialCase;
252            }
253            Visibility visibility = descriptor.getVisibility();
254            Integer defaultMapping = visibilityToAccessFlag.get(visibility);
255            if (defaultMapping == null) {
256                throw new IllegalStateException(visibility + " is not a valid visibility in backend for " + DescriptorRenderer.DEBUG_TEXT.render(descriptor));
257            }
258            return defaultMapping;
259        }
260    
261        /*
262            Use this method to get visibility flag for class to define it in byte code (v.defineClass method).
263            For other cases use getVisibilityAccessFlag(MemberDescriptor descriptor)
264            Classes in byte code should be public or package private
265         */
266        public static int getVisibilityAccessFlagForClass(@NotNull ClassDescriptor descriptor) {
267            if (descriptor instanceof SyntheticClassDescriptorForLambda) {
268                return getVisibilityAccessFlagForAnonymous(descriptor);
269            }
270            if (descriptor.getVisibility() == Visibilities.PUBLIC ||
271                descriptor.getVisibility() == Visibilities.PROTECTED ||
272                // TODO: should be package private, but for now Kotlin's reflection can't access members of such classes
273                descriptor.getVisibility() == Visibilities.LOCAL ||
274                descriptor.getVisibility() == Visibilities.INTERNAL) {
275                return ACC_PUBLIC;
276            }
277            return NO_FLAG_PACKAGE_PRIVATE;
278        }
279    
280        private static int getVisibilityAccessFlagForAnonymous(@NotNull ClassDescriptor descriptor) {
281            return InlineUtil.isInlineOrContainingInline(descriptor.getContainingDeclaration()) ? ACC_PUBLIC : NO_FLAG_PACKAGE_PRIVATE;
282        }
283    
284        public static int calculateInnerClassAccessFlags(@NotNull ClassDescriptor innerClass) {
285            int visibility =
286                    innerClass instanceof SyntheticClassDescriptorForLambda
287                    ? getVisibilityAccessFlagForAnonymous(innerClass)
288                    : innerClass.getVisibility() == Visibilities.LOCAL
289                      ? ACC_PUBLIC
290                      : getVisibilityAccessFlag(innerClass);
291            return visibility |
292                   innerAccessFlagsForModalityAndKind(innerClass) |
293                   (innerClass.isInner() ? 0 : ACC_STATIC);
294        }
295    
296        private static int innerAccessFlagsForModalityAndKind(@NotNull ClassDescriptor innerClass) {
297            switch (innerClass.getKind()) {
298                case INTERFACE:
299                    return ACC_ABSTRACT | ACC_INTERFACE;
300                case ENUM_CLASS:
301                    return ACC_FINAL | ACC_ENUM;
302                case ANNOTATION_CLASS:
303                    return ACC_ABSTRACT | ACC_ANNOTATION | ACC_INTERFACE;
304                default:
305                    Modality modality = innerClass.getModality();
306                    if (modality == Modality.FINAL) {
307                        return ACC_FINAL;
308                    }
309                    else if (modality == Modality.ABSTRACT || modality == Modality.SEALED) {
310                        return ACC_ABSTRACT;
311                    }
312            }
313            return 0;
314        }
315    
316        public static int getDeprecatedAccessFlag(@NotNull MemberDescriptor descriptor) {
317            if (descriptor instanceof PropertyAccessorDescriptor) {
318                return KotlinBuiltIns.isDeprecated(descriptor)
319                       ? ACC_DEPRECATED
320                       : getDeprecatedAccessFlag(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty());
321            }
322            else if (KotlinBuiltIns.isDeprecated(descriptor)) {
323                return ACC_DEPRECATED;
324            }
325            return 0;
326        }
327    
328        private static int getVarargsFlag(FunctionDescriptor functionDescriptor) {
329            if (!functionDescriptor.getValueParameters().isEmpty()
330                && functionDescriptor.getValueParameters().get(functionDescriptor.getValueParameters().size() - 1)
331                           .getVarargElementType() != null) {
332                return ACC_VARARGS;
333            }
334            return 0;
335        }
336    
337        @Nullable
338        private static Integer specialCaseVisibility(@NotNull MemberDescriptor memberDescriptor) {
339            DeclarationDescriptor containingDeclaration = memberDescriptor.getContainingDeclaration();
340            Visibility memberVisibility = memberDescriptor.getVisibility();
341    
342            if (isInlineOnlyOrReified(memberDescriptor)) return ACC_PRIVATE;
343    
344            if (memberVisibility == Visibilities.LOCAL && memberDescriptor instanceof CallableMemberDescriptor) {
345                return ACC_PUBLIC;
346            }
347    
348            if (isEnumEntry(memberDescriptor)) {
349                return NO_FLAG_PACKAGE_PRIVATE;
350            }
351    
352            if (memberDescriptor instanceof ConstructorDescriptor && isAnonymousObject(memberDescriptor.getContainingDeclaration())) {
353                return getVisibilityAccessFlagForAnonymous((ClassDescriptor) memberDescriptor.getContainingDeclaration());
354            }
355    
356            if (memberDescriptor instanceof SyntheticJavaPropertyDescriptor) {
357                return getVisibilityAccessFlag(((SyntheticJavaPropertyDescriptor) memberDescriptor).getGetMethod());
358            }
359            if (memberDescriptor instanceof PropertyAccessorDescriptor) {
360                PropertyDescriptor property = ((PropertyAccessorDescriptor) memberDescriptor).getCorrespondingProperty();
361                if (property instanceof SyntheticJavaPropertyDescriptor) {
362                    FunctionDescriptor method = memberDescriptor == property.getGetter()
363                                                ? ((SyntheticJavaPropertyDescriptor) property).getGetMethod()
364                                                : ((SyntheticJavaPropertyDescriptor) property).getSetMethod();
365                    assert method != null : "No get/set method in SyntheticJavaPropertyDescriptor: " + property;
366                    return getVisibilityAccessFlag(method);
367                }
368            }
369    
370            if (memberDescriptor instanceof CallableDescriptor && memberVisibility == Visibilities.PROTECTED) {
371                for (CallableDescriptor overridden : DescriptorUtils.getAllOverriddenDescriptors((CallableDescriptor) memberDescriptor)) {
372                    if (isJvmInterface(overridden.getContainingDeclaration())) {
373                        return ACC_PUBLIC;
374                    }
375                }
376            }
377    
378            if (!Visibilities.isPrivate(memberVisibility)) {
379                return null;
380            }
381    
382            // the following code is only for PRIVATE visibility of member
383            if (memberDescriptor instanceof ConstructorDescriptor) {
384                if (isEnumEntry(containingDeclaration)) {
385                    return NO_FLAG_PACKAGE_PRIVATE;
386                }
387                if (isEnumClass(containingDeclaration)) {
388                    //TODO: should be ACC_PRIVATE
389                    // see http://youtrack.jetbrains.com/issue/KT-2680
390                    return ACC_PROTECTED;
391                }
392            }
393    
394            return null;
395        }
396    
397        public static Type stringValueOfType(Type type) {
398            int sort = type.getSort();
399            return sort == Type.OBJECT || sort == Type.ARRAY
400                   ? OBJECT_TYPE
401                   : sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type;
402        }
403    
404        private static Type stringBuilderAppendType(Type type) {
405            switch (type.getSort()) {
406                case Type.OBJECT:
407                    return STRING_BUILDER_OBJECT_APPEND_ARG_TYPES.contains(type) ? type : OBJECT_TYPE;
408                case Type.ARRAY:
409                    return OBJECT_TYPE;
410                case Type.BYTE:
411                case Type.SHORT:
412                    return Type.INT_TYPE;
413                default:
414                    return type;
415            }
416        }
417    
418        public static void genThrow(@NotNull InstructionAdapter v, @NotNull String exception, @Nullable String message) {
419            v.anew(Type.getObjectType(exception));
420            v.dup();
421            if (message != null) {
422                v.aconst(message);
423                v.invokespecial(exception, "<init>", "(Ljava/lang/String;)V", false);
424            }
425            else {
426                v.invokespecial(exception, "<init>", "()V", false);
427            }
428            v.athrow();
429        }
430    
431        public static void genClosureFields(CalculatedClosure closure, ClassBuilder v, KotlinTypeMapper typeMapper) {
432            List<Pair<String, Type>> allFields = new ArrayList<Pair<String, Type>>();
433    
434            ClassifierDescriptor captureThis = closure.getCaptureThis();
435            if (captureThis != null) {
436                allFields.add(Pair.create(CAPTURED_THIS_FIELD, typeMapper.mapType(captureThis)));
437            }
438    
439            KotlinType captureReceiverType = closure.getCaptureReceiverType();
440            if (captureReceiverType != null) {
441                allFields.add(Pair.create(CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiverType)));
442            }
443    
444            allFields.addAll(closure.getRecordedFields());
445            genClosureFields(allFields, v);
446        }
447    
448        public static void genClosureFields(List<Pair<String, Type>> allFields, ClassBuilder builder) {
449            //noinspection PointlessBitwiseExpression
450            int access = NO_FLAG_PACKAGE_PRIVATE | ACC_SYNTHETIC | ACC_FINAL;
451            for (Pair<String, Type> field : allFields) {
452                builder.newField(JvmDeclarationOrigin.NO_ORIGIN, access, field.first, field.second.getDescriptor(), null, null);
453            }
454        }
455    
456        public static int genAssignInstanceFieldFromParam(FieldInfo info, int index, InstructionAdapter iv) {
457            assert !info.isStatic();
458            Type fieldType = info.getFieldType();
459            iv.load(0, info.getOwnerType());//this
460            iv.load(index, fieldType); //param
461            iv.visitFieldInsn(PUTFIELD, info.getOwnerInternalName(), info.getFieldName(), fieldType.getDescriptor());
462            index += fieldType.getSize();
463            return index;
464        }
465    
466        public static void genStringBuilderConstructor(InstructionAdapter v) {
467            v.visitTypeInsn(NEW, "java/lang/StringBuilder");
468            v.dup();
469            v.invokespecial("java/lang/StringBuilder", "<init>", "()V", false);
470        }
471    
472        public static void genInvokeAppendMethod(InstructionAdapter v, Type type) {
473            type = stringBuilderAppendType(type);
474            v.invokevirtual("java/lang/StringBuilder", "append", "(" + type.getDescriptor() + ")Ljava/lang/StringBuilder;", false);
475        }
476    
477        public static StackValue genToString(final StackValue receiver, final Type receiverType) {
478            return StackValue.operation(JAVA_STRING_TYPE, new Function1<InstructionAdapter, Unit>() {
479                @Override
480                public Unit invoke(InstructionAdapter v) {
481                    Type type = stringValueOfType(receiverType);
482                    receiver.put(type, v);
483                    v.invokestatic("java/lang/String", "valueOf", "(" + type.getDescriptor() + ")Ljava/lang/String;", false);
484                    return null;
485                }
486            });
487        }
488    
489        static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type) {
490            if (type.getSort() == Type.ARRAY) {
491                Type elementType = correctElementType(type);
492                if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
493                    iv.invokestatic("java/util/Arrays", "hashCode", "([Ljava/lang/Object;)I", false);
494                }
495                else {
496                    iv.invokestatic("java/util/Arrays", "hashCode", "(" + type.getDescriptor() + ")I", false);
497                }
498            }
499            else if (type.getSort() == Type.OBJECT) {
500                iv.invokevirtual("java/lang/Object", "hashCode", "()I", false);
501            }
502            else if (type.getSort() == Type.LONG) {
503                genLongHashCode(mv, iv);
504            }
505            else if (type.getSort() == Type.DOUBLE) {
506                iv.invokestatic("java/lang/Double", "doubleToLongBits", "(D)J", false);
507                genLongHashCode(mv, iv);
508            }
509            else if (type.getSort() == Type.FLOAT) {
510                iv.invokestatic("java/lang/Float", "floatToIntBits", "(F)I", false);
511            }
512            else if (type.getSort() == Type.BOOLEAN) {
513                Label end = new Label();
514                iv.dup();
515                iv.ifeq(end);
516                iv.pop();
517                iv.iconst(1);
518                iv.mark(end);
519            }
520            else { // byte short char int
521                // do nothing
522            }
523        }
524    
525        private static void genLongHashCode(MethodVisitor mv, InstructionAdapter iv) {
526            iv.dup2();
527            iv.iconst(32);
528            iv.ushr(Type.LONG_TYPE);
529            iv.xor(Type.LONG_TYPE);
530            mv.visitInsn(L2I);
531        }
532    
533        static void genInvertBoolean(InstructionAdapter v) {
534            v.iconst(1);
535            v.xor(Type.INT_TYPE);
536        }
537    
538        @NotNull
539        public static StackValue genEqualsForExpressionsOnStack(
540                final @NotNull IElementType opToken,
541                final @NotNull StackValue left,
542                final @NotNull StackValue right
543        ) {
544            final Type leftType = left.type;
545            final Type rightType = right.type;
546            if (isPrimitive(leftType) && leftType == rightType) {
547                return StackValue.cmp(opToken, leftType, left, right);
548            }
549    
550            return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() {
551                @Override
552                public Unit invoke(InstructionAdapter v) {
553                    left.put(leftType, v);
554                    right.put(rightType, v);
555                    genAreEqualCall(v);
556    
557                    if (opToken == KtTokens.EXCLEQ || opToken == KtTokens.EXCLEQEQEQ) {
558                        genInvertBoolean(v);
559                    }
560                    return Unit.INSTANCE;
561                }
562            });
563        }
564    
565        public static void genAreEqualCall(InstructionAdapter v) {
566            v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "areEqual", "(Ljava/lang/Object;Ljava/lang/Object;)Z", false);
567        }
568    
569        public static void numConst(int value, Type type, InstructionAdapter v) {
570            if (type == Type.FLOAT_TYPE) {
571                v.fconst(value);
572            }
573            else if (type == Type.DOUBLE_TYPE) {
574                v.dconst(value);
575            }
576            else if (type == Type.LONG_TYPE) {
577                v.lconst(value);
578            }
579            else if (type == Type.CHAR_TYPE || type == Type.BYTE_TYPE || type == Type.SHORT_TYPE || type == Type.INT_TYPE) {
580                v.iconst(value);
581            }
582            else {
583                throw new IllegalArgumentException("Primitive numeric type expected, got: " + type);
584            }
585        }
586    
587        public static void genIncrement(Type baseType, int myDelta, InstructionAdapter v) {
588            Type operationType = numberFunctionOperandType(baseType);
589            numConst(myDelta, operationType, v);
590            v.add(operationType);
591            StackValue.coerce(operationType, baseType, v);
592        }
593    
594        public static void swap(InstructionAdapter v, Type stackTop, Type afterTop) {
595            if (stackTop.getSize() == 1) {
596                if (afterTop.getSize() == 1) {
597                    v.swap();
598                }
599                else {
600                    v.dupX2();
601                    v.pop();
602                }
603            }
604            else {
605                if (afterTop.getSize() == 1) {
606                    v.dup2X1();
607                }
608                else {
609                    v.dup2X2();
610                }
611                v.pop2();
612            }
613        }
614    
615        public static void genNotNullAssertionsForParameters(
616                @NotNull InstructionAdapter v,
617                @NotNull GenerationState state,
618                @NotNull FunctionDescriptor descriptor,
619                @NotNull FrameMap frameMap
620        ) {
621            if (!state.isParamAssertionsEnabled()) return;
622    
623            // Private method is not accessible from other classes, no assertions needed
624            if (getVisibilityAccessFlag(descriptor) == ACC_PRIVATE) return;
625    
626            ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
627            if (receiverParameter != null) {
628                genParamAssertion(v, state.getTypeMapper(), frameMap, receiverParameter, "$receiver");
629            }
630    
631            for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) {
632                genParamAssertion(v, state.getTypeMapper(), frameMap, parameter, parameter.getName().asString());
633            }
634        }
635    
636        private static void genParamAssertion(
637                @NotNull InstructionAdapter v,
638                @NotNull KotlinTypeMapper typeMapper,
639                @NotNull FrameMap frameMap,
640                @NotNull CallableDescriptor parameter,
641                @NotNull String name
642        ) {
643            KotlinType type = parameter.getReturnType();
644            if (type == null || isNullableType(type)) return;
645    
646            int index = frameMap.getIndex(parameter);
647            Type asmType = typeMapper.mapType(type);
648            if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
649                v.load(index, asmType);
650                v.visitLdcInsn(name);
651                v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "checkParameterIsNotNull",
652                               "(Ljava/lang/Object;Ljava/lang/String;)V", false);
653            }
654        }
655    
656        @NotNull
657        public static StackValue genNotNullAssertions(
658                @NotNull GenerationState state,
659                @NotNull final StackValue stackValue,
660                @Nullable final RuntimeAssertionInfo runtimeAssertionInfo
661        ) {
662            if (!state.isCallAssertionsEnabled()) return stackValue;
663            if (runtimeAssertionInfo == null || !runtimeAssertionInfo.getNeedNotNullAssertion()) return stackValue;
664    
665            return new StackValue(stackValue.type) {
666    
667                @Override
668                public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
669                    stackValue.put(type, v);
670                    if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
671                        v.dup();
672                        v.visitLdcInsn(runtimeAssertionInfo.getMessage());
673                        v.invokestatic("kotlin/jvm/internal/Intrinsics", "checkExpressionValueIsNotNull",
674                                       "(Ljava/lang/Object;Ljava/lang/String;)V", false);
675                    }
676                }
677            };
678        }
679    
680        public static void pushDefaultValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
681            if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
682                v.aconst(null);
683            }
684            else {
685                pushDefaultPrimitiveValueOnStack(type, v);
686            }
687        }
688    
689        public static void pushDefaultPrimitiveValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
690            if (type.getSort() == Type.FLOAT) {
691                v.fconst(0);
692            }
693            else if (type.getSort() == Type.DOUBLE) {
694                v.dconst(0);
695            }
696            else if (type.getSort() == Type.LONG) {
697                v.lconst(0);
698            }
699            else {
700                v.iconst(0);
701            }
702        }
703    
704        public static boolean isInstancePropertyWithStaticBackingField(@NotNull PropertyDescriptor propertyDescriptor) {
705            return propertyDescriptor.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE &&
706                   isObject(propertyDescriptor.getContainingDeclaration());
707        }
708    
709        public static int getVisibilityForBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) {
710            boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null;
711            if (isDelegate || isExtensionProperty) {
712                return ACC_PRIVATE;
713            }
714            else {
715                return propertyDescriptor.isLateInit() || isConstOrHasJvmFieldAnnotation(propertyDescriptor)
716                       ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor))
717                       : ACC_PRIVATE;
718            }
719        }
720    
721        private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) {
722            if (!propertyDescriptor.isVar()) {
723                return propertyDescriptor;
724            }
725            else {
726                return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor;
727            }
728        }
729    
730        public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
731            DeclarationDescriptor propertyContainer = propertyDescriptor.getContainingDeclaration();
732            return propertyDescriptor.isConst()
733                   && isCompanionObject(propertyContainer) && isInterface(propertyContainer.getContainingDeclaration())
734                   && getVisibilityForBackingField(propertyDescriptor, false) == ACC_PUBLIC;
735        }
736    
737        public static Type comparisonOperandType(Type left, Type right) {
738            if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE;
739            if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE;
740            if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE;
741            return Type.INT_TYPE;
742        }
743    
744        @NotNull
745        public static Type numberFunctionOperandType(@NotNull Type expectedType) {
746            if (expectedType == Type.SHORT_TYPE || expectedType == Type.BYTE_TYPE || expectedType == Type.CHAR_TYPE) {
747                return Type.INT_TYPE;
748            }
749            return expectedType;
750        }
751    
752        public static void pop(@NotNull MethodVisitor v, @NotNull Type type) {
753            if (type.getSize() == 2) {
754                v.visitInsn(Opcodes.POP2);
755            }
756            else {
757                v.visitInsn(Opcodes.POP);
758            }
759        }
760    
761        public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) {
762            dup(v, type.getSize());
763        }
764    
765        private static void dup(@NotNull InstructionAdapter v, int size) {
766            if (size == 2) {
767                v.dup2();
768            }
769            else if (size == 1) {
770                v.dup();
771            }
772            else {
773                throw new UnsupportedOperationException();
774            }
775        }
776    
777        public static void dup(@NotNull InstructionAdapter v, @NotNull Type topOfStack, @NotNull Type afterTop) {
778            if (topOfStack.getSize() == 0 && afterTop.getSize() == 0) {
779                return;
780            }
781    
782            if (topOfStack.getSize() == 0) {
783                dup(v, afterTop);
784            }
785            else if (afterTop.getSize() == 0) {
786                dup(v, topOfStack);
787            }
788            else if (afterTop.getSize() == 1) {
789                if (topOfStack.getSize() == 1) {
790                    dup(v, 2);
791                }
792                else {
793                    v.dup2X1();
794                    v.pop2();
795                    v.dupX2();
796                    v.dupX2();
797                    v.pop();
798                    v.dup2X1();
799                }
800            }
801            else {
802                //Note: it's possible to write dup3 and dup4
803                throw new UnsupportedOperationException("Don't know how generate dup3/dup4 for: " + topOfStack + " and " + afterTop);
804            }
805        }
806    
807        public static void writeAnnotationData(
808                @NotNull AnnotationVisitor av,
809                @NotNull DescriptorSerializer serializer,
810                @NotNull MessageLite message
811        ) {
812            byte[] bytes = serializer.serialize(message);
813    
814            AnnotationVisitor data = av.visitArray(JvmAnnotationNames.METADATA_DATA_FIELD_NAME);
815            for (String string : BitEncoding.encodeBytes(bytes)) {
816                data.visit(null, string);
817            }
818            data.visitEnd();
819    
820            AnnotationVisitor strings = av.visitArray(JvmAnnotationNames.METADATA_STRINGS_FIELD_NAME);
821            for (String string : ((JvmStringTable) serializer.getStringTable()).getStrings()) {
822                strings.visit(null, string);
823            }
824            strings.visitEnd();
825        }
826    
827        @NotNull
828        public static Type asmTypeByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
829            return Type.getObjectType(internalNameByFqNameWithoutInnerClasses(fqName));
830        }
831    
832        @NotNull
833        public static String internalNameByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
834            return JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName();
835        }
836    
837        public static void putJavaLangClassInstance(@NotNull InstructionAdapter v, @NotNull Type type) {
838            if (isPrimitive(type)) {
839                v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;");
840            }
841            else {
842                v.aconst(type);
843            }
844        }
845    
846        public static void wrapJavaClassIntoKClass(@NotNull InstructionAdapter v) {
847            v.invokestatic(REFLECTION, "getOrCreateKotlinClass", Type.getMethodDescriptor(K_CLASS_TYPE, getType(Class.class)), false);
848        }
849    
850        public static void wrapJavaClassesIntoKClasses(@NotNull InstructionAdapter v) {
851            v.invokestatic(REFLECTION, "getOrCreateKotlinClasses", Type.getMethodDescriptor(K_CLASS_ARRAY_TYPE, getType(Class[].class)), false);
852        }
853    
854        public static int getReceiverIndex(@NotNull CodegenContext context, @NotNull CallableMemberDescriptor descriptor) {
855            OwnerKind kind = context.getContextKind();
856            //Trait always should have this descriptor
857            return kind != OwnerKind.DEFAULT_IMPLS && isStaticMethod(kind, descriptor) ? 0 : 1;
858        }
859    }