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