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                   AnnotationUtilKt.isPlatformStaticInObjectOrClass(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 (AnnotationUtilKt.isPlatformStaticInCompanionObject(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.isHiddenInResolution(functionDescriptor)
235                || functionDescriptor instanceof PropertyAccessorDescriptor
236                   && DeprecationUtilKt.isHiddenInResolution(((PropertyAccessorDescriptor) functionDescriptor).getCorrespondingProperty())) {
237                flags |= ACC_SYNTHETIC;
238            }
239            return flags;
240        }
241    
242        //TODO: move mapping logic to front-end java
243        public static int getVisibilityAccessFlag(@NotNull MemberDescriptor descriptor) {
244            Integer specialCase = specialCaseVisibility(descriptor);
245            if (specialCase != null) {
246                return specialCase;
247            }
248            Visibility visibility = descriptor.getVisibility();
249            Integer defaultMapping = visibilityToAccessFlag.get(visibility);
250            if (defaultMapping == null) {
251                throw new IllegalStateException(visibility + " is not a valid visibility in backend for " + DescriptorRenderer.DEBUG_TEXT.render(descriptor));
252            }
253            return defaultMapping;
254        }
255    
256        /*
257            Use this method to get visibility flag for class to define it in byte code (v.defineClass method).
258            For other cases use getVisibilityAccessFlag(MemberDescriptor descriptor)
259            Classes in byte code should be public or package private
260         */
261        public static int getVisibilityAccessFlagForClass(@NotNull ClassDescriptor descriptor) {
262            if (descriptor instanceof SyntheticClassDescriptorForLambda) {
263                return getVisibilityAccessFlagForAnonymous(descriptor);
264            }
265            if (descriptor.getVisibility() == Visibilities.PUBLIC ||
266                descriptor.getVisibility() == Visibilities.PROTECTED ||
267                // TODO: should be package private, but for now Kotlin's reflection can't access members of such classes
268                descriptor.getVisibility() == Visibilities.LOCAL ||
269                descriptor.getVisibility() == Visibilities.INTERNAL) {
270                return ACC_PUBLIC;
271            }
272            return NO_FLAG_PACKAGE_PRIVATE;
273        }
274    
275        private static int getVisibilityAccessFlagForAnonymous(@NotNull ClassDescriptor descriptor) {
276            return InlineUtil.isInlineOrContainingInline(descriptor.getContainingDeclaration()) ? ACC_PUBLIC : NO_FLAG_PACKAGE_PRIVATE;
277        }
278    
279        public static int calculateInnerClassAccessFlags(@NotNull ClassDescriptor innerClass) {
280            int visibility =
281                    innerClass instanceof SyntheticClassDescriptorForLambda
282                    ? getVisibilityAccessFlagForAnonymous(innerClass)
283                    : innerClass.getVisibility() == Visibilities.LOCAL
284                      ? ACC_PUBLIC
285                      : getVisibilityAccessFlag(innerClass);
286            return visibility |
287                   innerAccessFlagsForModalityAndKind(innerClass) |
288                   (innerClass.isInner() ? 0 : ACC_STATIC);
289        }
290    
291        private static int innerAccessFlagsForModalityAndKind(@NotNull ClassDescriptor innerClass) {
292            switch (innerClass.getKind()) {
293                case INTERFACE:
294                    return ACC_ABSTRACT | ACC_INTERFACE;
295                case ENUM_CLASS:
296                    return ACC_FINAL | ACC_ENUM;
297                case ANNOTATION_CLASS:
298                    return ACC_ABSTRACT | ACC_ANNOTATION | ACC_INTERFACE;
299                default:
300                    if (innerClass.getModality() == Modality.FINAL) {
301                        return ACC_FINAL;
302                    }
303                    else if (innerClass.getModality() == Modality.ABSTRACT) {
304                        return ACC_ABSTRACT;
305                    }
306            }
307            return 0;
308        }
309    
310        public static int getDeprecatedAccessFlag(@NotNull MemberDescriptor descriptor) {
311            if (descriptor instanceof PropertyAccessorDescriptor) {
312                return KotlinBuiltIns.isDeprecated(descriptor)
313                       ? ACC_DEPRECATED
314                       : getDeprecatedAccessFlag(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty());
315            }
316            else if (KotlinBuiltIns.isDeprecated(descriptor)) {
317                return ACC_DEPRECATED;
318            }
319            return 0;
320        }
321    
322        private static int getVarargsFlag(FunctionDescriptor functionDescriptor) {
323            if (!functionDescriptor.getValueParameters().isEmpty()
324                && functionDescriptor.getValueParameters().get(functionDescriptor.getValueParameters().size() - 1)
325                           .getVarargElementType() != null) {
326                return ACC_VARARGS;
327            }
328            return 0;
329        }
330    
331        @Nullable
332        private static Integer specialCaseVisibility(@NotNull MemberDescriptor memberDescriptor) {
333            DeclarationDescriptor containingDeclaration = memberDescriptor.getContainingDeclaration();
334            Visibility memberVisibility = memberDescriptor.getVisibility();
335    
336            if (AnnotationUtilKt.isInlineOnlyOrReified(memberDescriptor)) return ACC_PRIVATE;
337    
338            if (memberVisibility == Visibilities.LOCAL && memberDescriptor instanceof CallableMemberDescriptor) {
339                return ACC_PUBLIC;
340            }
341    
342            if (isEnumEntry(memberDescriptor)) {
343                return NO_FLAG_PACKAGE_PRIVATE;
344            }
345    
346            if (memberDescriptor instanceof ConstructorDescriptor && isAnonymousObject(memberDescriptor.getContainingDeclaration())) {
347                return getVisibilityAccessFlagForAnonymous((ClassDescriptor) memberDescriptor.getContainingDeclaration());
348            }
349    
350            if (memberDescriptor instanceof SyntheticJavaPropertyDescriptor) {
351                return getVisibilityAccessFlag(((SyntheticJavaPropertyDescriptor) memberDescriptor).getGetMethod());
352            }
353            if (memberDescriptor instanceof PropertyAccessorDescriptor) {
354                PropertyDescriptor property = ((PropertyAccessorDescriptor) memberDescriptor).getCorrespondingProperty();
355                if (property instanceof SyntheticJavaPropertyDescriptor) {
356                    FunctionDescriptor method = memberDescriptor == property.getGetter()
357                                                ? ((SyntheticJavaPropertyDescriptor) property).getGetMethod()
358                                                : ((SyntheticJavaPropertyDescriptor) property).getSetMethod();
359                    assert method != null : "No get/set method in SyntheticJavaPropertyDescriptor: " + property;
360                    return getVisibilityAccessFlag(method);
361                }
362            }
363    
364            if (memberDescriptor instanceof CallableDescriptor && memberVisibility == Visibilities.PROTECTED) {
365                for (CallableDescriptor overridden : DescriptorUtils.getAllOverriddenDescriptors((CallableDescriptor) memberDescriptor)) {
366                    if (isJvmInterface(overridden.getContainingDeclaration())) {
367                        return ACC_PUBLIC;
368                    }
369                }
370            }
371    
372            if (!Visibilities.isPrivate(memberVisibility)) {
373                return null;
374            }
375    
376            // the following code is only for PRIVATE visibility of member
377            if (memberDescriptor instanceof ConstructorDescriptor) {
378                if (isEnumEntry(containingDeclaration)) {
379                    return NO_FLAG_PACKAGE_PRIVATE;
380                }
381                if (isEnumClass(containingDeclaration)) {
382                    //TODO: should be ACC_PRIVATE
383                    // see http://youtrack.jetbrains.com/issue/KT-2680
384                    return ACC_PROTECTED;
385                }
386            }
387    
388            return null;
389        }
390    
391        public static Type stringValueOfType(Type type) {
392            int sort = type.getSort();
393            return sort == Type.OBJECT || sort == Type.ARRAY
394                   ? OBJECT_TYPE
395                   : sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type;
396        }
397    
398        private static Type stringBuilderAppendType(Type type) {
399            switch (type.getSort()) {
400                case Type.OBJECT:
401                    return STRING_BUILDER_OBJECT_APPEND_ARG_TYPES.contains(type) ? type : OBJECT_TYPE;
402                case Type.ARRAY:
403                    return OBJECT_TYPE;
404                case Type.BYTE:
405                case Type.SHORT:
406                    return Type.INT_TYPE;
407                default:
408                    return type;
409            }
410        }
411    
412        public static void genThrow(@NotNull InstructionAdapter v, @NotNull String exception, @Nullable String message) {
413            v.anew(Type.getObjectType(exception));
414            v.dup();
415            if (message != null) {
416                v.aconst(message);
417                v.invokespecial(exception, "<init>", "(Ljava/lang/String;)V", false);
418            }
419            else {
420                v.invokespecial(exception, "<init>", "()V", false);
421            }
422            v.athrow();
423        }
424    
425        public static void genClosureFields(CalculatedClosure closure, ClassBuilder v, KotlinTypeMapper typeMapper) {
426            List<Pair<String, Type>> allFields = new ArrayList<Pair<String, Type>>();
427    
428            ClassifierDescriptor captureThis = closure.getCaptureThis();
429            if (captureThis != null) {
430                allFields.add(Pair.create(CAPTURED_THIS_FIELD, typeMapper.mapType(captureThis)));
431            }
432    
433            KotlinType captureReceiverType = closure.getCaptureReceiverType();
434            if (captureReceiverType != null) {
435                allFields.add(Pair.create(CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiverType)));
436            }
437    
438            allFields.addAll(closure.getRecordedFields());
439            genClosureFields(allFields, v);
440        }
441    
442        public static void genClosureFields(List<Pair<String, Type>> allFields, ClassBuilder builder) {
443            //noinspection PointlessBitwiseExpression
444            int access = NO_FLAG_PACKAGE_PRIVATE | ACC_SYNTHETIC | ACC_FINAL;
445            for (Pair<String, Type> field : allFields) {
446                builder.newField(JvmDeclarationOrigin.NO_ORIGIN, access, field.first, field.second.getDescriptor(), null, null);
447            }
448        }
449    
450        public static int genAssignInstanceFieldFromParam(FieldInfo info, int index, InstructionAdapter iv) {
451            assert !info.isStatic();
452            Type fieldType = info.getFieldType();
453            iv.load(0, info.getOwnerType());//this
454            iv.load(index, fieldType); //param
455            iv.visitFieldInsn(PUTFIELD, info.getOwnerInternalName(), info.getFieldName(), fieldType.getDescriptor());
456            index += fieldType.getSize();
457            return index;
458        }
459    
460        public static void genStringBuilderConstructor(InstructionAdapter v) {
461            v.visitTypeInsn(NEW, "java/lang/StringBuilder");
462            v.dup();
463            v.invokespecial("java/lang/StringBuilder", "<init>", "()V", false);
464        }
465    
466        public static void genInvokeAppendMethod(InstructionAdapter v, Type type) {
467            type = stringBuilderAppendType(type);
468            v.invokevirtual("java/lang/StringBuilder", "append", "(" + type.getDescriptor() + ")Ljava/lang/StringBuilder;", false);
469        }
470    
471        public static StackValue genToString(final StackValue receiver, final Type receiverType) {
472            return StackValue.operation(JAVA_STRING_TYPE, new Function1<InstructionAdapter, Unit>() {
473                @Override
474                public Unit invoke(InstructionAdapter v) {
475                    Type type = stringValueOfType(receiverType);
476                    receiver.put(type, v);
477                    v.invokestatic("java/lang/String", "valueOf", "(" + type.getDescriptor() + ")Ljava/lang/String;", false);
478                    return null;
479                }
480            });
481        }
482    
483        static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type) {
484            if (type.getSort() == Type.ARRAY) {
485                Type elementType = correctElementType(type);
486                if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
487                    iv.invokestatic("java/util/Arrays", "hashCode", "([Ljava/lang/Object;)I", false);
488                }
489                else {
490                    iv.invokestatic("java/util/Arrays", "hashCode", "(" + type.getDescriptor() + ")I", false);
491                }
492            }
493            else if (type.getSort() == Type.OBJECT) {
494                iv.invokevirtual("java/lang/Object", "hashCode", "()I", false);
495            }
496            else if (type.getSort() == Type.LONG) {
497                genLongHashCode(mv, iv);
498            }
499            else if (type.getSort() == Type.DOUBLE) {
500                iv.invokestatic("java/lang/Double", "doubleToLongBits", "(D)J", false);
501                genLongHashCode(mv, iv);
502            }
503            else if (type.getSort() == Type.FLOAT) {
504                iv.invokestatic("java/lang/Float", "floatToIntBits", "(F)I", false);
505            }
506            else if (type.getSort() == Type.BOOLEAN) {
507                Label end = new Label();
508                iv.dup();
509                iv.ifeq(end);
510                iv.pop();
511                iv.iconst(1);
512                iv.mark(end);
513            }
514            else { // byte short char int
515                // do nothing
516            }
517        }
518    
519        private static void genLongHashCode(MethodVisitor mv, InstructionAdapter iv) {
520            iv.dup2();
521            iv.iconst(32);
522            iv.ushr(Type.LONG_TYPE);
523            iv.xor(Type.LONG_TYPE);
524            mv.visitInsn(L2I);
525        }
526    
527        static void genInvertBoolean(InstructionAdapter v) {
528            v.iconst(1);
529            v.xor(Type.INT_TYPE);
530        }
531    
532        @NotNull
533        public static StackValue genEqualsForExpressionsOnStack(
534                final @NotNull IElementType opToken,
535                final @NotNull StackValue left,
536                final @NotNull StackValue right
537        ) {
538            final Type leftType = left.type;
539            final Type rightType = right.type;
540            if (isPrimitive(leftType) && leftType == rightType) {
541                return StackValue.cmp(opToken, leftType, left, right);
542            }
543    
544            return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() {
545                @Override
546                public Unit invoke(InstructionAdapter v) {
547                    left.put(leftType, v);
548                    right.put(rightType, v);
549                    genAreEqualCall(v);
550    
551                    if (opToken == KtTokens.EXCLEQ || opToken == KtTokens.EXCLEQEQEQ) {
552                        genInvertBoolean(v);
553                    }
554                    return Unit.INSTANCE;
555                }
556            });
557        }
558    
559        public static void genAreEqualCall(InstructionAdapter v) {
560            v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "areEqual", "(Ljava/lang/Object;Ljava/lang/Object;)Z", false);
561        }
562    
563        public static void numConst(int value, Type type, InstructionAdapter v) {
564            if (type == Type.FLOAT_TYPE) {
565                v.fconst(value);
566            }
567            else if (type == Type.DOUBLE_TYPE) {
568                v.dconst(value);
569            }
570            else if (type == Type.LONG_TYPE) {
571                v.lconst(value);
572            }
573            else if (type == Type.CHAR_TYPE || type == Type.BYTE_TYPE || type == Type.SHORT_TYPE || type == Type.INT_TYPE) {
574                v.iconst(value);
575            }
576            else {
577                throw new IllegalArgumentException("Primitive numeric type expected, got: " + type);
578            }
579        }
580    
581        public static void genIncrement(Type baseType, int myDelta, InstructionAdapter v) {
582            Type operationType = numberFunctionOperandType(baseType);
583            numConst(myDelta, operationType, v);
584            v.add(operationType);
585            StackValue.coerce(operationType, baseType, v);
586        }
587    
588        public static void swap(InstructionAdapter v, Type stackTop, Type afterTop) {
589            if (stackTop.getSize() == 1) {
590                if (afterTop.getSize() == 1) {
591                    v.swap();
592                }
593                else {
594                    v.dupX2();
595                    v.pop();
596                }
597            }
598            else {
599                if (afterTop.getSize() == 1) {
600                    v.dup2X1();
601                }
602                else {
603                    v.dup2X2();
604                }
605                v.pop2();
606            }
607        }
608    
609        public static void genNotNullAssertionsForParameters(
610                @NotNull InstructionAdapter v,
611                @NotNull GenerationState state,
612                @NotNull FunctionDescriptor descriptor,
613                @NotNull FrameMap frameMap
614        ) {
615            if (!state.isParamAssertionsEnabled()) return;
616    
617            // Private method is not accessible from other classes, no assertions needed
618            if (getVisibilityAccessFlag(descriptor) == ACC_PRIVATE) return;
619    
620            ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
621            if (receiverParameter != null) {
622                genParamAssertion(v, state.getTypeMapper(), frameMap, receiverParameter, "$receiver");
623            }
624    
625            for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) {
626                genParamAssertion(v, state.getTypeMapper(), frameMap, parameter, parameter.getName().asString());
627            }
628        }
629    
630        private static void genParamAssertion(
631                @NotNull InstructionAdapter v,
632                @NotNull KotlinTypeMapper typeMapper,
633                @NotNull FrameMap frameMap,
634                @NotNull CallableDescriptor parameter,
635                @NotNull String name
636        ) {
637            KotlinType type = parameter.getReturnType();
638            if (type == null || isNullableType(type)) return;
639            
640            int index = frameMap.getIndex(parameter);
641            Type asmType = typeMapper.mapType(type);
642            if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
643                v.load(index, asmType);
644                v.visitLdcInsn(name);
645                v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "checkParameterIsNotNull",
646                               "(Ljava/lang/Object;Ljava/lang/String;)V", false);
647            }
648        }
649    
650        @NotNull
651        public static StackValue genNotNullAssertions(
652                @NotNull GenerationState state,
653                @NotNull final StackValue stackValue,
654                @Nullable final RuntimeAssertionInfo runtimeAssertionInfo
655        ) {
656            if (!state.isCallAssertionsEnabled()) return stackValue;
657            if (runtimeAssertionInfo == null || !runtimeAssertionInfo.getNeedNotNullAssertion()) return stackValue;
658    
659            return new StackValue(stackValue.type) {
660    
661                @Override
662                public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
663                    stackValue.put(type, v);
664                    if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
665                        v.dup();
666                        v.visitLdcInsn(runtimeAssertionInfo.getMessage());
667                        v.invokestatic("kotlin/jvm/internal/Intrinsics", "checkExpressionValueIsNotNull",
668                                       "(Ljava/lang/Object;Ljava/lang/String;)V", false);
669                    }
670                }
671            };
672        }
673    
674        public static void pushDefaultValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
675            if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
676                v.aconst(null);
677            }
678            else {
679                pushDefaultPrimitiveValueOnStack(type, v);
680            }
681        }
682    
683        public static void pushDefaultPrimitiveValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
684            if (type.getSort() == Type.FLOAT) {
685                v.fconst(0);
686            }
687            else if (type.getSort() == Type.DOUBLE) {
688                v.dconst(0);
689            }
690            else if (type.getSort() == Type.LONG) {
691                v.lconst(0);
692            }
693            else {
694                v.iconst(0);
695            }
696        }
697    
698        public static boolean isInstancePropertyWithStaticBackingField(@NotNull PropertyDescriptor propertyDescriptor) {
699            return propertyDescriptor.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE &&
700                   isObject(propertyDescriptor.getContainingDeclaration());
701        }
702    
703        public static int getVisibilityForBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) {
704            boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null;
705            if (isDelegate || isExtensionProperty) {
706                return ACC_PRIVATE;
707            }
708            else {
709                return propertyDescriptor.isLateInit() || isConstOrHasJvmFieldAnnotation(propertyDescriptor)
710                       ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor))
711                       : ACC_PRIVATE;
712            }
713        }
714    
715        private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) {
716            if (!propertyDescriptor.isVar()) {
717                return propertyDescriptor;
718            }
719            else {
720                return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor;
721            }
722        }
723    
724        public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
725            DeclarationDescriptor propertyContainer = propertyDescriptor.getContainingDeclaration();
726            return propertyDescriptor.isConst()
727                   && isCompanionObject(propertyContainer) && isInterface(propertyContainer.getContainingDeclaration())
728                   && getVisibilityForBackingField(propertyDescriptor, false) == ACC_PUBLIC;
729        }
730    
731        public static Type comparisonOperandType(Type left, Type right) {
732            if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE;
733            if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE;
734            if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE;
735            return Type.INT_TYPE;
736        }
737    
738        @NotNull
739        public static Type numberFunctionOperandType(@NotNull Type expectedType) {
740            if (expectedType == Type.SHORT_TYPE || expectedType == Type.BYTE_TYPE || expectedType == Type.CHAR_TYPE) {
741                return Type.INT_TYPE;
742            }
743            return expectedType;
744        }
745    
746        public static void pop(@NotNull MethodVisitor v, @NotNull Type type) {
747            if (type.getSize() == 2) {
748                v.visitInsn(Opcodes.POP2);
749            }
750            else {
751                v.visitInsn(Opcodes.POP);
752            }
753        }
754    
755        public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) {
756            dup(v, type.getSize());
757        }
758    
759        private static void dup(@NotNull InstructionAdapter v, int size) {
760            if (size == 2) {
761                v.dup2();
762            }
763            else if (size == 1) {
764                v.dup();
765            }
766            else {
767                throw new UnsupportedOperationException();
768            }
769        }
770    
771        public static void dup(@NotNull InstructionAdapter v, @NotNull Type topOfStack, @NotNull Type afterTop) {
772            if (topOfStack.getSize() == 0 && afterTop.getSize() == 0) {
773                return;
774            }
775    
776            if (topOfStack.getSize() == 0) {
777                dup(v, afterTop);
778            }
779            else if (afterTop.getSize() == 0) {
780                dup(v, topOfStack);
781            }
782            else if (afterTop.getSize() == 1) {
783                if (topOfStack.getSize() == 1) {
784                    dup(v, 2);
785                }
786                else {
787                    v.dup2X1();
788                    v.pop2();
789                    v.dupX2();
790                    v.dupX2();
791                    v.pop();
792                    v.dup2X1();
793                }
794            }
795            else {
796                //Note: it's possible to write dup3 and dup4
797                throw new UnsupportedOperationException("Don't know how generate dup3/dup4 for: " + topOfStack + " and " + afterTop);
798            }
799        }
800    
801        public static void writeAnnotationData(
802                @NotNull AnnotationVisitor av,
803                @NotNull DescriptorSerializer serializer,
804                @NotNull MessageLite message
805        ) {
806            byte[] bytes = serializer.serialize(message);
807    
808            AnnotationVisitor data = av.visitArray(JvmAnnotationNames.METADATA_DATA_FIELD_NAME);
809            for (String string : BitEncoding.encodeBytes(bytes)) {
810                data.visit(null, string);
811            }
812            data.visitEnd();
813    
814            AnnotationVisitor strings = av.visitArray(JvmAnnotationNames.METADATA_STRINGS_FIELD_NAME);
815            for (String string : ((JvmStringTable) serializer.getStringTable()).getStrings()) {
816                strings.visit(null, string);
817            }
818            strings.visitEnd();
819        }
820    
821        @NotNull
822        public static Type asmTypeByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
823            return Type.getObjectType(internalNameByFqNameWithoutInnerClasses(fqName));
824        }
825    
826        @NotNull
827        public static String internalNameByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
828            return JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName();
829        }
830    
831        @NotNull
832        public static String getSimpleInternalName(@NotNull String internalName) {
833            int lastSlash = internalName.lastIndexOf('/');
834            if (lastSlash >= 0) {
835                return internalName.substring(lastSlash + 1);
836            }
837            else {
838                return internalName;
839            }
840        }
841    
842        public static void putJavaLangClassInstance(@NotNull InstructionAdapter v, @NotNull Type type) {
843            if (isPrimitive(type)) {
844                v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;");
845            }
846            else {
847                v.aconst(type);
848            }
849        }
850    
851        public static void wrapJavaClassIntoKClass(@NotNull InstructionAdapter v) {
852            v.invokestatic(REFLECTION, "getOrCreateKotlinClass", Type.getMethodDescriptor(K_CLASS_TYPE, getType(Class.class)), false);
853        }
854    
855        public static void wrapJavaClassesIntoKClasses(@NotNull InstructionAdapter v) {
856            v.invokestatic(REFLECTION, "getOrCreateKotlinClasses", Type.getMethodDescriptor(K_CLASS_ARRAY_TYPE, getType(Class[].class)), false);
857        }
858    
859        public static int getReceiverIndex(@NotNull CodegenContext context, @NotNull CallableMemberDescriptor descriptor) {
860            OwnerKind kind = context.getContextKind();
861            //Trait always should have this descriptor
862            return kind != OwnerKind.DEFAULT_IMPLS && isStaticMethod(kind, descriptor) ? 0 : 1;
863        }
864    }