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