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