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.KotlinTypeMapper;
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.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 genIncrement(Type expectedType, int myDelta, InstructionAdapter v) {
566            numConst(myDelta, expectedType, v);
567            v.add(expectedType);
568        }
569    
570        public static void numConst(int value, Type type, InstructionAdapter v) {
571            if (type == Type.FLOAT_TYPE) {
572                v.fconst(value);
573            }
574            else if (type == Type.DOUBLE_TYPE) {
575                v.dconst(value);
576            }
577            else if (type == Type.LONG_TYPE) {
578                v.lconst(value);
579            }
580            else if (type == Type.CHAR_TYPE || type == Type.BYTE_TYPE || type == Type.SHORT_TYPE || type == Type.INT_TYPE) {
581                v.iconst(value);
582            }
583            else {
584                throw new IllegalArgumentException("Primitive numeric type expected, got: " + type);
585            }
586        }
587    
588        public static void genIncrement(Type expectedType, Type baseType, int myDelta, InstructionAdapter v) {
589            genIncrement(baseType, myDelta, v);
590            StackValue.coerce(baseType, expectedType, v);
591        }
592    
593        public static void swap(InstructionAdapter v, Type stackTop, Type afterTop) {
594            if (stackTop.getSize() == 1) {
595                if (afterTop.getSize() == 1) {
596                    v.swap();
597                }
598                else {
599                    v.dupX2();
600                    v.pop();
601                }
602            }
603            else {
604                if (afterTop.getSize() == 1) {
605                    v.dup2X1();
606                }
607                else {
608                    v.dup2X2();
609                }
610                v.pop2();
611            }
612        }
613    
614        public static void genNotNullAssertionsForParameters(
615                @NotNull InstructionAdapter v,
616                @NotNull GenerationState state,
617                @NotNull FunctionDescriptor descriptor,
618                @NotNull FrameMap frameMap
619        ) {
620            if (!state.isParamAssertionsEnabled()) return;
621    
622            // Private method is not accessible from other classes, no assertions needed
623            if (getVisibilityAccessFlag(descriptor) == ACC_PRIVATE) return;
624    
625            ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
626            if (receiverParameter != null) {
627                genParamAssertion(v, state.getTypeMapper(), frameMap, receiverParameter, "$receiver");
628            }
629    
630            for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) {
631                genParamAssertion(v, state.getTypeMapper(), frameMap, parameter, parameter.getName().asString());
632            }
633        }
634    
635        private static void genParamAssertion(
636                @NotNull InstructionAdapter v,
637                @NotNull KotlinTypeMapper typeMapper,
638                @NotNull FrameMap frameMap,
639                @NotNull CallableDescriptor parameter,
640                @NotNull String name
641        ) {
642            KotlinType type = parameter.getReturnType();
643            if (type == null || isNullableType(type)) return;
644            
645            int index = frameMap.getIndex(parameter);
646            Type asmType = typeMapper.mapType(type);
647            if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
648                v.load(index, asmType);
649                v.visitLdcInsn(name);
650                v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "checkParameterIsNotNull",
651                               "(Ljava/lang/Object;Ljava/lang/String;)V", false);
652            }
653        }
654    
655        @NotNull
656        public static StackValue genNotNullAssertions(
657                @NotNull GenerationState state,
658                @NotNull final StackValue stackValue,
659                @Nullable final RuntimeAssertionInfo runtimeAssertionInfo
660        ) {
661            if (!state.isCallAssertionsEnabled()) return stackValue;
662            if (runtimeAssertionInfo == null || !runtimeAssertionInfo.getNeedNotNullAssertion()) return stackValue;
663    
664            return new StackValue(stackValue.type) {
665    
666                @Override
667                public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
668                    stackValue.put(type, v);
669                    if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
670                        v.dup();
671                        v.visitLdcInsn(runtimeAssertionInfo.getMessage());
672                        v.invokestatic("kotlin/jvm/internal/Intrinsics", "checkExpressionValueIsNotNull",
673                                       "(Ljava/lang/Object;Ljava/lang/String;)V", false);
674                    }
675                }
676            };
677        }
678    
679        public static void pushDefaultValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
680            if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
681                v.aconst(null);
682            }
683            else {
684                pushDefaultPrimitiveValueOnStack(type, v);
685            }
686        }
687    
688        public static void pushDefaultPrimitiveValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
689            if (type.getSort() == Type.FLOAT) {
690                v.fconst(0);
691            }
692            else if (type.getSort() == Type.DOUBLE) {
693                v.dconst(0);
694            }
695            else if (type.getSort() == Type.LONG) {
696                v.lconst(0);
697            }
698            else {
699                v.iconst(0);
700            }
701        }
702    
703        public static boolean isInstancePropertyWithStaticBackingField(@NotNull PropertyDescriptor propertyDescriptor) {
704            return propertyDescriptor.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE &&
705                   isObject(propertyDescriptor.getContainingDeclaration());
706        }
707    
708        public static int getVisibilityForBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) {
709            boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null;
710            if (isDelegate || isExtensionProperty) {
711                return ACC_PRIVATE;
712            }
713            else {
714                return propertyDescriptor.isLateInit() || isConstOrHasJvmFieldAnnotation(propertyDescriptor)
715                       ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor))
716                       : ACC_PRIVATE;
717            }
718        }
719    
720        private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) {
721            if (!propertyDescriptor.isVar()) {
722                return propertyDescriptor;
723            }
724            else {
725                return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor;
726            }
727        }
728    
729        public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
730            DeclarationDescriptor propertyContainer = propertyDescriptor.getContainingDeclaration();
731            return propertyDescriptor.isConst()
732                   && isCompanionObject(propertyContainer) && isInterface(propertyContainer.getContainingDeclaration())
733                   && getVisibilityForBackingField(propertyDescriptor, false) == ACC_PUBLIC;
734        }
735    
736        public static Type comparisonOperandType(Type left, Type right) {
737            if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE;
738            if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE;
739            if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE;
740            return Type.INT_TYPE;
741        }
742    
743        @NotNull
744        public static Type numberFunctionOperandType(@NotNull Type expectedType) {
745            if (expectedType == Type.SHORT_TYPE || expectedType == Type.BYTE_TYPE || expectedType == Type.CHAR_TYPE) {
746                return Type.INT_TYPE;
747            }
748            return expectedType;
749        }
750    
751        public static void pop(@NotNull MethodVisitor v, @NotNull Type type) {
752            if (type.getSize() == 2) {
753                v.visitInsn(Opcodes.POP2);
754            }
755            else {
756                v.visitInsn(Opcodes.POP);
757            }
758        }
759    
760        public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) {
761            dup(v, type.getSize());
762        }
763    
764        private static void dup(@NotNull InstructionAdapter v, int size) {
765            if (size == 2) {
766                v.dup2();
767            }
768            else if (size == 1) {
769                v.dup();
770            }
771            else {
772                throw new UnsupportedOperationException();
773            }
774        }
775    
776        public static void dup(@NotNull InstructionAdapter v, @NotNull Type topOfStack, @NotNull Type afterTop) {
777            if (topOfStack.getSize() == 0 && afterTop.getSize() == 0) {
778                return;
779            }
780    
781            if (topOfStack.getSize() == 0) {
782                dup(v, afterTop);
783            }
784            else if (afterTop.getSize() == 0) {
785                dup(v, topOfStack);
786            }
787            else if (afterTop.getSize() == 1) {
788                if (topOfStack.getSize() == 1) {
789                    dup(v, 2);
790                }
791                else {
792                    v.dup2X1();
793                    v.pop2();
794                    v.dupX2();
795                    v.dupX2();
796                    v.pop();
797                    v.dup2X1();
798                }
799            }
800            else {
801                //Note: it's possible to write dup3 and dup4
802                throw new UnsupportedOperationException("Don't know how generate dup3/dup4 for: " + topOfStack + " and " + afterTop);
803            }
804        }
805    
806        public static void writeAnnotationData(
807                @NotNull AnnotationVisitor av,
808                @NotNull DescriptorSerializer serializer,
809                @NotNull MessageLite message
810        ) {
811            byte[] bytes = serializer.serialize(message);
812    
813            AnnotationVisitor data = av.visitArray(JvmAnnotationNames.METADATA_DATA_FIELD_NAME);
814            for (String string : BitEncoding.encodeBytes(bytes)) {
815                data.visit(null, string);
816            }
817            data.visitEnd();
818    
819            AnnotationVisitor strings = av.visitArray(JvmAnnotationNames.METADATA_STRINGS_FIELD_NAME);
820            for (String string : ((JvmStringTable) serializer.getStringTable()).getStrings()) {
821                strings.visit(null, string);
822            }
823            strings.visitEnd();
824        }
825    
826        @NotNull
827        public static Type asmTypeByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
828            return Type.getObjectType(internalNameByFqNameWithoutInnerClasses(fqName));
829        }
830    
831        @NotNull
832        public static String internalNameByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
833            return JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName();
834        }
835    
836        @NotNull
837        public static String getSimpleInternalName(@NotNull String internalName) {
838            int lastSlash = internalName.lastIndexOf('/');
839            if (lastSlash >= 0) {
840                return internalName.substring(lastSlash + 1);
841            }
842            else {
843                return internalName;
844            }
845        }
846    
847        public static void putJavaLangClassInstance(@NotNull InstructionAdapter v, @NotNull Type type) {
848            if (isPrimitive(type)) {
849                v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;");
850            }
851            else {
852                v.aconst(type);
853            }
854        }
855    
856        public static void wrapJavaClassIntoKClass(@NotNull InstructionAdapter v) {
857            v.invokestatic(REFLECTION, "getOrCreateKotlinClass", Type.getMethodDescriptor(K_CLASS_TYPE, getType(Class.class)), false);
858        }
859    
860        public static void wrapJavaClassesIntoKClasses(@NotNull InstructionAdapter v) {
861            v.invokestatic(REFLECTION, "getOrCreateKotlinClasses", Type.getMethodDescriptor(K_CLASS_ARRAY_TYPE, getType(Class[].class)), false);
862        }
863    
864        public static int getReceiverIndex(@NotNull CodegenContext context, @NotNull CallableMemberDescriptor descriptor) {
865            OwnerKind kind = context.getContextKind();
866            //Trait always should have this descriptor
867            return kind != OwnerKind.DEFAULT_IMPLS && isStaticMethod(kind, descriptor) ? 0 : 1;
868        }
869    }