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