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