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