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