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