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