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