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