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.descriptors.*;
036    import org.jetbrains.kotlin.lexer.KtTokens;
037    import org.jetbrains.kotlin.load.java.JavaVisibilities;
038    import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
039    import org.jetbrains.kotlin.name.FqName;
040    import org.jetbrains.kotlin.protobuf.MessageLite;
041    import org.jetbrains.kotlin.renderer.DescriptorRenderer;
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.RuntimeAssertionInfo;
049    import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
050    import org.jetbrains.kotlin.serialization.DescriptorSerializer;
051    import org.jetbrains.kotlin.serialization.jvm.BitEncoding;
052    import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor;
053    import org.jetbrains.kotlin.types.KotlinType;
054    import org.jetbrains.org.objectweb.asm.*;
055    import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
056    import org.jetbrains.org.objectweb.asm.commons.Method;
057    
058    import java.util.ArrayList;
059    import java.util.List;
060    import java.util.Map;
061    import java.util.Set;
062    
063    import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isBoolean;
064    import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isPrimitiveClass;
065    import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConstOrHasJvmFieldAnnotation;
066    import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface;
067    import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
068    import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
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 = unboxPrimitiveTypeOrNull(boxedType);
125            if (primitiveType == null) {
126                throw new UnsupportedOperationException("Unboxing: " + boxedType);
127            }
128            return primitiveType;
129        }
130    
131        @Nullable
132        public static Type unboxPrimitiveTypeOrNull(@NotNull Type boxedType) {
133            return primitiveTypeByBoxedType.get(boxedType);
134        }
135    
136        public static boolean isIntPrimitive(Type type) {
137            return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE;
138        }
139    
140        public static boolean isNumberPrimitive(Type type) {
141            return isIntPrimitive(type) || type == Type.FLOAT_TYPE || type == Type.DOUBLE_TYPE || type == Type.LONG_TYPE;
142        }
143    
144        public static boolean isPrimitive(Type type) {
145            return type.getSort() != Type.OBJECT && type.getSort() != Type.ARRAY;
146        }
147    
148        public static boolean isPrimitiveNumberClassDescriptor(DeclarationDescriptor descriptor) {
149            if (!(descriptor instanceof ClassDescriptor)) {
150                return false;
151            }
152            return isPrimitiveClass((ClassDescriptor) descriptor) && !isBoolean((ClassDescriptor) descriptor);
153        }
154    
155        public static Type correctElementType(Type type) {
156            String internalName = type.getInternalName();
157            assert internalName.charAt(0) == '[';
158            return Type.getType(internalName.substring(1));
159        }
160    
161        @Nullable
162        public static PrimitiveType asmPrimitiveTypeToLangPrimitiveType(Type type) {
163            JvmPrimitiveType jvmPrimitiveType = primitiveTypeByAsmSort.get(type.getSort());
164            return jvmPrimitiveType != null ? jvmPrimitiveType.getPrimitiveType() : null;
165        }
166    
167        @NotNull
168        public static Method method(@NotNull String name, @NotNull Type returnType, @NotNull Type... parameterTypes) {
169            return new Method(name, Type.getMethodDescriptor(returnType, parameterTypes));
170        }
171    
172        public static boolean isAbstractMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) {
173            return (functionDescriptor.getModality() == Modality.ABSTRACT
174                    || isJvmInterface(functionDescriptor.getContainingDeclaration()))
175                   && !isStaticMethod(kind, functionDescriptor);
176        }
177    
178        public static boolean isStaticMethod(OwnerKind kind, CallableMemberDescriptor functionDescriptor) {
179            return isStaticKind(kind) ||
180                   KotlinTypeMapper.isStaticAccessor(functionDescriptor) ||
181                   CodegenUtilKt.isJvmStaticInObjectOrClass(functionDescriptor);
182        }
183    
184        public static boolean isStaticKind(OwnerKind kind) {
185            return kind == OwnerKind.PACKAGE || kind == OwnerKind.DEFAULT_IMPLS;
186        }
187    
188        public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind) {
189            int flags = getCommonCallableFlags(functionDescriptor);
190    
191            for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.METHOD_FLAGS) {
192                if (flagAnnotation.hasAnnotation(functionDescriptor.getOriginal())) {
193                    flags |= flagAnnotation.getJvmFlag();
194                }
195            }
196    
197            if (functionDescriptor.getOriginal().isExternal()) {
198                flags |= Opcodes.ACC_NATIVE;
199            }
200    
201            if (CodegenUtilKt.isJvmStaticInCompanionObject(functionDescriptor)) {
202                // Native method will be a member of the class, the companion object method will be delegated to it
203                flags &= ~Opcodes.ACC_NATIVE;
204            }
205    
206            if (functionDescriptor.getModality() == Modality.FINAL && !(functionDescriptor instanceof ConstructorDescriptor)) {
207                DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration();
208                if (!(containingDeclaration instanceof ClassDescriptor) ||
209                    ((ClassDescriptor) containingDeclaration).getKind() != ClassKind.INTERFACE) {
210                    flags |= ACC_FINAL;
211                }
212            }
213    
214            if (isStaticMethod(kind, functionDescriptor)) {
215                flags |= ACC_STATIC;
216            }
217    
218            if (isAbstractMethod(functionDescriptor, kind)) {
219                flags |= ACC_ABSTRACT;
220            }
221    
222            if (KotlinTypeMapper.isAccessor(functionDescriptor)
223                || AnnotationUtilKt.hasJvmSyntheticAnnotation(functionDescriptor)) {
224                flags |= ACC_SYNTHETIC;
225            }
226    
227            return flags;
228        }
229    
230        private static int getCommonCallableFlags(FunctionDescriptor functionDescriptor) {
231            int flags = getVisibilityAccessFlag(functionDescriptor);
232            flags |= getVarargsFlag(functionDescriptor);
233            flags |= getDeprecatedAccessFlag(functionDescriptor);
234            if (DeprecationUtilKt.isDeprecatedHidden(functionDescriptor)
235                || functionDescriptor instanceof PropertyAccessorDescriptor
236                   && DeprecationUtilKt.isDeprecatedHidden(((PropertyAccessorDescriptor) functionDescriptor).getCorrespondingProperty())) {
237                flags |= ACC_SYNTHETIC;
238            }
239            return flags;
240        }
241    
242        public static int getVisibilityAccessFlag(@NotNull MemberDescriptor descriptor) {
243            Integer specialCase = specialCaseVisibility(descriptor);
244            if (specialCase != null) {
245                return specialCase;
246            }
247            Visibility visibility = descriptor.getVisibility();
248            Integer defaultMapping = visibilityToAccessFlag.get(visibility);
249            if (defaultMapping == null) {
250                throw new IllegalStateException(visibility + " is not a valid visibility in backend for " + DescriptorRenderer.DEBUG_TEXT.render(descriptor));
251            }
252            return defaultMapping;
253        }
254    
255        /*
256            Use this method to get visibility flag for class to define it in byte code (v.defineClass method).
257            For other cases use getVisibilityAccessFlag(MemberDescriptor descriptor)
258            Classes in byte code should be public or package private
259         */
260        public static int getVisibilityAccessFlagForClass(@NotNull ClassDescriptor descriptor) {
261            if (descriptor instanceof SyntheticClassDescriptorForLambda) {
262                return getVisibilityAccessFlagForAnonymous(descriptor);
263            }
264            if (descriptor.getVisibility() == Visibilities.PUBLIC ||
265                descriptor.getVisibility() == Visibilities.PROTECTED ||
266                // TODO: should be package private, but for now Kotlin's reflection can't access members of such classes
267                descriptor.getVisibility() == Visibilities.LOCAL ||
268                descriptor.getVisibility() == Visibilities.INTERNAL) {
269                return ACC_PUBLIC;
270            }
271            return NO_FLAG_PACKAGE_PRIVATE;
272        }
273    
274        private static int getVisibilityAccessFlagForAnonymous(@NotNull ClassDescriptor descriptor) {
275            return InlineUtil.isInlineOrContainingInline(descriptor.getContainingDeclaration()) ? ACC_PUBLIC : NO_FLAG_PACKAGE_PRIVATE;
276        }
277    
278        public static int calculateInnerClassAccessFlags(@NotNull ClassDescriptor innerClass) {
279            int visibility =
280                    innerClass instanceof SyntheticClassDescriptorForLambda
281                    ? getVisibilityAccessFlagForAnonymous(innerClass)
282                    : innerClass.getVisibility() == Visibilities.LOCAL
283                      ? ACC_PUBLIC
284                      : getVisibilityAccessFlag(innerClass);
285            return visibility |
286                   innerAccessFlagsForModalityAndKind(innerClass) |
287                   (innerClass.isInner() ? 0 : ACC_STATIC);
288        }
289    
290        private static int innerAccessFlagsForModalityAndKind(@NotNull ClassDescriptor innerClass) {
291            switch (innerClass.getKind()) {
292                case INTERFACE:
293                    return ACC_ABSTRACT | ACC_INTERFACE;
294                case ENUM_CLASS:
295                    return ACC_FINAL | ACC_ENUM;
296                case ANNOTATION_CLASS:
297                    return ACC_ABSTRACT | ACC_ANNOTATION | ACC_INTERFACE;
298                default:
299                    if (innerClass.getModality() == Modality.FINAL) {
300                        return ACC_FINAL;
301                    }
302                    else if (innerClass.getModality() == Modality.ABSTRACT) {
303                        return ACC_ABSTRACT;
304                    }
305            }
306            return 0;
307        }
308    
309        public static int getDeprecatedAccessFlag(@NotNull MemberDescriptor descriptor) {
310            if (descriptor instanceof PropertyAccessorDescriptor) {
311                return KotlinBuiltIns.isDeprecated(descriptor)
312                       ? ACC_DEPRECATED
313                       : getDeprecatedAccessFlag(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty());
314            }
315            else if (KotlinBuiltIns.isDeprecated(descriptor)) {
316                return ACC_DEPRECATED;
317            }
318            return 0;
319        }
320    
321        private static int getVarargsFlag(FunctionDescriptor functionDescriptor) {
322            if (!functionDescriptor.getValueParameters().isEmpty()
323                && functionDescriptor.getValueParameters().get(functionDescriptor.getValueParameters().size() - 1)
324                           .getVarargElementType() != null) {
325                return ACC_VARARGS;
326            }
327            return 0;
328        }
329    
330        @Nullable
331        private static Integer specialCaseVisibility(@NotNull MemberDescriptor memberDescriptor) {
332            DeclarationDescriptor containingDeclaration = memberDescriptor.getContainingDeclaration();
333            Visibility memberVisibility = memberDescriptor.getVisibility();
334    
335            if (AnnotationUtilKt.isInlineOnlyOrReified(memberDescriptor)) return ACC_PRIVATE;
336    
337            if (memberVisibility == Visibilities.LOCAL && memberDescriptor instanceof CallableMemberDescriptor) {
338                return ACC_PUBLIC;
339            }
340    
341            if (isEnumEntry(memberDescriptor)) {
342                return NO_FLAG_PACKAGE_PRIVATE;
343            }
344    
345            if (memberDescriptor instanceof ConstructorDescriptor && isAnonymousObject(memberDescriptor.getContainingDeclaration())) {
346                return getVisibilityAccessFlagForAnonymous((ClassDescriptor) memberDescriptor.getContainingDeclaration());
347            }
348    
349            if (memberDescriptor instanceof SyntheticJavaPropertyDescriptor) {
350                return getVisibilityAccessFlag(((SyntheticJavaPropertyDescriptor) memberDescriptor).getGetMethod());
351            }
352            if (memberDescriptor instanceof PropertyAccessorDescriptor) {
353                PropertyDescriptor property = ((PropertyAccessorDescriptor) memberDescriptor).getCorrespondingProperty();
354                if (property instanceof SyntheticJavaPropertyDescriptor) {
355                    FunctionDescriptor method = memberDescriptor == property.getGetter()
356                                                ? ((SyntheticJavaPropertyDescriptor) property).getGetMethod()
357                                                : ((SyntheticJavaPropertyDescriptor) property).getSetMethod();
358                    assert method != null : "No get/set method in SyntheticJavaPropertyDescriptor: " + property;
359                    return getVisibilityAccessFlag(method);
360                }
361            }
362    
363            if (memberDescriptor instanceof CallableDescriptor && memberVisibility == Visibilities.PROTECTED) {
364                for (CallableDescriptor overridden : DescriptorUtils.getAllOverriddenDescriptors((CallableDescriptor) memberDescriptor)) {
365                    if (isJvmInterface(overridden.getContainingDeclaration())) {
366                        return ACC_PUBLIC;
367                    }
368                }
369            }
370    
371            if (!Visibilities.isPrivate(memberVisibility)) {
372                return null;
373            }
374    
375            // the following code is only for PRIVATE visibility of member
376            if (memberDescriptor instanceof ConstructorDescriptor) {
377                if (isEnumEntry(containingDeclaration)) {
378                    return NO_FLAG_PACKAGE_PRIVATE;
379                }
380                if (isEnumClass(containingDeclaration)) {
381                    //TODO: should be ACC_PRIVATE
382                    // see http://youtrack.jetbrains.com/issue/KT-2680
383                    return ACC_PROTECTED;
384                }
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, KotlinTypeMapper 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 numConst(int value, Type type, InstructionAdapter v) {
563            if (type == Type.FLOAT_TYPE) {
564                v.fconst(value);
565            }
566            else if (type == Type.DOUBLE_TYPE) {
567                v.dconst(value);
568            }
569            else if (type == Type.LONG_TYPE) {
570                v.lconst(value);
571            }
572            else if (type == Type.CHAR_TYPE || type == Type.BYTE_TYPE || type == Type.SHORT_TYPE || type == Type.INT_TYPE) {
573                v.iconst(value);
574            }
575            else {
576                throw new IllegalArgumentException("Primitive numeric type expected, got: " + type);
577            }
578        }
579    
580        public static void genIncrement(Type baseType, int myDelta, InstructionAdapter v) {
581            Type operationType = numberFunctionOperandType(baseType);
582            numConst(myDelta, operationType, v);
583            v.add(operationType);
584            StackValue.coerce(operationType, baseType, v);
585        }
586    
587        public static void swap(InstructionAdapter v, Type stackTop, Type afterTop) {
588            if (stackTop.getSize() == 1) {
589                if (afterTop.getSize() == 1) {
590                    v.swap();
591                }
592                else {
593                    v.dupX2();
594                    v.pop();
595                }
596            }
597            else {
598                if (afterTop.getSize() == 1) {
599                    v.dup2X1();
600                }
601                else {
602                    v.dup2X2();
603                }
604                v.pop2();
605            }
606        }
607    
608        public static void genNotNullAssertionsForParameters(
609                @NotNull InstructionAdapter v,
610                @NotNull GenerationState state,
611                @NotNull FunctionDescriptor descriptor,
612                @NotNull FrameMap frameMap
613        ) {
614            if (!state.isParamAssertionsEnabled()) return;
615    
616            // Private method is not accessible from other classes, no assertions needed
617            if (getVisibilityAccessFlag(descriptor) == ACC_PRIVATE) return;
618    
619            ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
620            if (receiverParameter != null) {
621                genParamAssertion(v, state.getTypeMapper(), frameMap, receiverParameter, "$receiver");
622            }
623    
624            for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) {
625                genParamAssertion(v, state.getTypeMapper(), frameMap, parameter, parameter.getName().asString());
626            }
627        }
628    
629        private static void genParamAssertion(
630                @NotNull InstructionAdapter v,
631                @NotNull KotlinTypeMapper typeMapper,
632                @NotNull FrameMap frameMap,
633                @NotNull CallableDescriptor parameter,
634                @NotNull String name
635        ) {
636            KotlinType type = parameter.getReturnType();
637            if (type == null || isNullableType(type)) return;
638    
639            int index = frameMap.getIndex(parameter);
640            Type asmType = typeMapper.mapType(type);
641            if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
642                v.load(index, asmType);
643                v.visitLdcInsn(name);
644                v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "checkParameterIsNotNull",
645                               "(Ljava/lang/Object;Ljava/lang/String;)V", false);
646            }
647        }
648    
649        @NotNull
650        public static StackValue genNotNullAssertions(
651                @NotNull GenerationState state,
652                @NotNull final StackValue stackValue,
653                @Nullable final RuntimeAssertionInfo runtimeAssertionInfo
654        ) {
655            if (!state.isCallAssertionsEnabled()) return stackValue;
656            if (runtimeAssertionInfo == null || !runtimeAssertionInfo.getNeedNotNullAssertion()) return stackValue;
657    
658            return new StackValue(stackValue.type) {
659    
660                @Override
661                public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
662                    stackValue.put(type, v);
663                    if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
664                        v.dup();
665                        v.visitLdcInsn(runtimeAssertionInfo.getMessage());
666                        v.invokestatic("kotlin/jvm/internal/Intrinsics", "checkExpressionValueIsNotNull",
667                                       "(Ljava/lang/Object;Ljava/lang/String;)V", false);
668                    }
669                }
670            };
671        }
672    
673        public static void pushDefaultValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
674            if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
675                v.aconst(null);
676            }
677            else {
678                pushDefaultPrimitiveValueOnStack(type, v);
679            }
680        }
681    
682        public static void pushDefaultPrimitiveValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
683            if (type.getSort() == Type.FLOAT) {
684                v.fconst(0);
685            }
686            else if (type.getSort() == Type.DOUBLE) {
687                v.dconst(0);
688            }
689            else if (type.getSort() == Type.LONG) {
690                v.lconst(0);
691            }
692            else {
693                v.iconst(0);
694            }
695        }
696    
697        public static boolean isInstancePropertyWithStaticBackingField(@NotNull PropertyDescriptor propertyDescriptor) {
698            return propertyDescriptor.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE &&
699                   isObject(propertyDescriptor.getContainingDeclaration());
700        }
701    
702        public static int getVisibilityForBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) {
703            boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null;
704            if (isDelegate || isExtensionProperty) {
705                return ACC_PRIVATE;
706            }
707            else {
708                return propertyDescriptor.isLateInit() || isConstOrHasJvmFieldAnnotation(propertyDescriptor)
709                       ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor))
710                       : ACC_PRIVATE;
711            }
712        }
713    
714        private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) {
715            if (!propertyDescriptor.isVar()) {
716                return propertyDescriptor;
717            }
718            else {
719                return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor;
720            }
721        }
722    
723        public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
724            DeclarationDescriptor propertyContainer = propertyDescriptor.getContainingDeclaration();
725            return propertyDescriptor.isConst()
726                   && isCompanionObject(propertyContainer) && isInterface(propertyContainer.getContainingDeclaration())
727                   && getVisibilityForBackingField(propertyDescriptor, false) == ACC_PUBLIC;
728        }
729    
730        public static Type comparisonOperandType(Type left, Type right) {
731            if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE;
732            if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE;
733            if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE;
734            return Type.INT_TYPE;
735        }
736    
737        @NotNull
738        public static Type numberFunctionOperandType(@NotNull Type expectedType) {
739            if (expectedType == Type.SHORT_TYPE || expectedType == Type.BYTE_TYPE || expectedType == Type.CHAR_TYPE) {
740                return Type.INT_TYPE;
741            }
742            return expectedType;
743        }
744    
745        public static void pop(@NotNull MethodVisitor v, @NotNull Type type) {
746            if (type.getSize() == 2) {
747                v.visitInsn(Opcodes.POP2);
748            }
749            else {
750                v.visitInsn(Opcodes.POP);
751            }
752        }
753    
754        public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) {
755            dup(v, type.getSize());
756        }
757    
758        private static void dup(@NotNull InstructionAdapter v, int size) {
759            if (size == 2) {
760                v.dup2();
761            }
762            else if (size == 1) {
763                v.dup();
764            }
765            else {
766                throw new UnsupportedOperationException();
767            }
768        }
769    
770        public static void dup(@NotNull InstructionAdapter v, @NotNull Type topOfStack, @NotNull Type afterTop) {
771            if (topOfStack.getSize() == 0 && afterTop.getSize() == 0) {
772                return;
773            }
774    
775            if (topOfStack.getSize() == 0) {
776                dup(v, afterTop);
777            }
778            else if (afterTop.getSize() == 0) {
779                dup(v, topOfStack);
780            }
781            else if (afterTop.getSize() == 1) {
782                if (topOfStack.getSize() == 1) {
783                    dup(v, 2);
784                }
785                else {
786                    v.dup2X1();
787                    v.pop2();
788                    v.dupX2();
789                    v.dupX2();
790                    v.pop();
791                    v.dup2X1();
792                }
793            }
794            else {
795                //Note: it's possible to write dup3 and dup4
796                throw new UnsupportedOperationException("Don't know how generate dup3/dup4 for: " + topOfStack + " and " + afterTop);
797            }
798        }
799    
800        public static void writeAnnotationData(
801                @NotNull AnnotationVisitor av,
802                @NotNull DescriptorSerializer serializer,
803                @NotNull MessageLite message
804        ) {
805            byte[] bytes = serializer.serialize(message);
806    
807            AnnotationVisitor data = av.visitArray(JvmAnnotationNames.METADATA_DATA_FIELD_NAME);
808            for (String string : BitEncoding.encodeBytes(bytes)) {
809                data.visit(null, string);
810            }
811            data.visitEnd();
812    
813            AnnotationVisitor strings = av.visitArray(JvmAnnotationNames.METADATA_STRINGS_FIELD_NAME);
814            for (String string : ((JvmStringTable) serializer.getStringTable()).getStrings()) {
815                strings.visit(null, string);
816            }
817            strings.visitEnd();
818        }
819    
820        @NotNull
821        public static Type asmTypeByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
822            return Type.getObjectType(internalNameByFqNameWithoutInnerClasses(fqName));
823        }
824    
825        @NotNull
826        public static String internalNameByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
827            return JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName();
828        }
829    
830        public static void putJavaLangClassInstance(@NotNull InstructionAdapter v, @NotNull Type type) {
831            if (isPrimitive(type)) {
832                v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;");
833            }
834            else {
835                v.aconst(type);
836            }
837        }
838    
839        public static void wrapJavaClassIntoKClass(@NotNull InstructionAdapter v) {
840            v.invokestatic(REFLECTION, "getOrCreateKotlinClass", Type.getMethodDescriptor(K_CLASS_TYPE, getType(Class.class)), false);
841        }
842    
843        public static void wrapJavaClassesIntoKClasses(@NotNull InstructionAdapter v) {
844            v.invokestatic(REFLECTION, "getOrCreateKotlinClasses", Type.getMethodDescriptor(K_CLASS_ARRAY_TYPE, getType(Class[].class)), false);
845        }
846    
847        public static int getReceiverIndex(@NotNull CodegenContext context, @NotNull CallableMemberDescriptor descriptor) {
848            OwnerKind kind = context.getContextKind();
849            //Trait always should have this descriptor
850            return kind != OwnerKind.DEFAULT_IMPLS && isStaticMethod(kind, descriptor) ? 0 : 1;
851        }
852    }