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            ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
601            if (receiverParameter != null) {
602                genParamAssertion(v, state.getTypeMapper(), frameMap, receiverParameter, "$receiver");
603            }
604    
605            for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) {
606                genParamAssertion(v, state.getTypeMapper(), frameMap, parameter, parameter.getName().asString());
607            }
608        }
609    
610        private static void genParamAssertion(
611                @NotNull InstructionAdapter v,
612                @NotNull JetTypeMapper typeMapper,
613                @NotNull FrameMap frameMap,
614                @NotNull CallableDescriptor parameter,
615                @NotNull String name
616        ) {
617            JetType type = parameter.getReturnType();
618            if (type == null || isNullableType(type)) return;
619            
620            int index = frameMap.getIndex(parameter);
621            Type asmType = typeMapper.mapType(type);
622            if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
623                v.load(index, asmType);
624                v.visitLdcInsn(name);
625                v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "checkParameterIsNotNull",
626                               "(Ljava/lang/Object;Ljava/lang/String;)V", false);
627            }
628        }
629    
630        public static void genNotNullAssertionForField(
631                @NotNull InstructionAdapter v,
632                @NotNull GenerationState state,
633                @NotNull PropertyDescriptor descriptor
634        ) {
635            genNotNullAssertion(v, state, descriptor, "checkFieldIsNotNull");
636        }
637    
638        public static void genNotNullAssertionForMethod(
639                @NotNull InstructionAdapter v,
640                @NotNull GenerationState state,
641                @NotNull ResolvedCall resolvedCall
642        ) {
643            CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
644            if (descriptor instanceof ConstructorDescriptor) return;
645    
646            genNotNullAssertion(v, state, descriptor, "checkReturnedValueIsNotNull");
647        }
648    
649        private static void genNotNullAssertion(
650                @NotNull InstructionAdapter v,
651                @NotNull GenerationState state,
652                @NotNull CallableDescriptor descriptor,
653                @NotNull String assertMethodToCall
654        ) {
655            // Assertions are generated elsewhere for platform types
656            if (JvmPackage.getPLATFORM_TYPES()) return;
657    
658            if (!state.isCallAssertionsEnabled()) return;
659    
660            if (!isDeclaredInJava(descriptor)) return;
661    
662            JetType type = descriptor.getReturnType();
663            if (type == null || isNullableType(TypesPackage.lowerIfFlexible(type))) return;
664    
665            Type asmType = state.getTypeMapper().mapReturnType(descriptor);
666            if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
667                v.dup();
668                v.visitLdcInsn(descriptor.getContainingDeclaration().getName().asString());
669                v.visitLdcInsn(descriptor.getName().asString());
670                v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, assertMethodToCall,
671                               "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V", false);
672            }
673        }
674    
675        @NotNull
676        public static StackValue genNotNullAssertions(
677                @NotNull GenerationState state,
678                @NotNull final StackValue stackValue,
679                @Nullable final Approximation.Info approximationInfo
680        ) {
681            if (!state.isCallAssertionsEnabled()) return stackValue;
682            if (approximationInfo == null || !TypesPackage.assertNotNull(approximationInfo)) return stackValue;
683    
684            return new StackValue(stackValue.type) {
685    
686                @Override
687                public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
688                    stackValue.put(type, v);
689                    if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
690                        v.dup();
691                        v.visitLdcInsn(approximationInfo.getMessage());
692                        v.invokestatic("kotlin/jvm/internal/Intrinsics", "checkExpressionValueIsNotNull",
693                                       "(Ljava/lang/Object;Ljava/lang/String;)V", false);
694                    }
695                }
696            };
697        }
698    
699        private static boolean isDeclaredInJava(@NotNull CallableDescriptor callableDescriptor) {
700            CallableDescriptor descriptor = callableDescriptor;
701            while (true) {
702                if (descriptor instanceof JavaCallableMemberDescriptor) {
703                    return true;
704                }
705                CallableDescriptor original = descriptor.getOriginal();
706                if (descriptor == original) break;
707                descriptor = original;
708            }
709            return false;
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            if (propertyDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
738                return false;
739            }
740    
741            return isObject(propertyDescriptor.getContainingDeclaration()) || isPropertyWithBackingFieldInOuterClass(propertyDescriptor);
742        }
743    
744        public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
745            return propertyDescriptor.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE &&
746                   isClassObjectWithBackingFieldsInOuter(propertyDescriptor.getContainingDeclaration());
747        }
748    
749        public static int getVisibilityForSpecialPropertyBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) {
750            boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null;
751            if (isDelegate || isExtensionProperty) {
752                return ACC_PRIVATE;
753            }
754            else {
755                return areBothAccessorDefault(propertyDescriptor)
756                       ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor))
757                       : ACC_PRIVATE;
758            }
759        }
760    
761        private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) {
762            if (!propertyDescriptor.isVar()) {
763                return propertyDescriptor;
764            }
765            else {
766                return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor;
767            }
768        }
769    
770        public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
771            boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null;
772            DeclarationDescriptor propertyContainer = propertyDescriptor.getContainingDeclaration();
773            return !propertyDescriptor.isVar()
774                   && !isExtensionProperty
775                   && isClassObject(propertyContainer) && isTrait(propertyContainer.getContainingDeclaration())
776                   && areBothAccessorDefault(propertyDescriptor)
777                   && getVisibilityForSpecialPropertyBackingField(propertyDescriptor, false) == ACC_PUBLIC;
778        }
779    
780        public static boolean isClassObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor classObject) {
781            DeclarationDescriptor containingClass = classObject.getContainingDeclaration();
782            return isClassObject(classObject) && (isClass(containingClass) || isEnumClass(containingClass));
783        }
784    
785        private static boolean areBothAccessorDefault(@NotNull PropertyDescriptor propertyDescriptor) {
786            return isAccessorWithEmptyBody(propertyDescriptor.getGetter())
787                   && (!propertyDescriptor.isVar() || isAccessorWithEmptyBody(propertyDescriptor.getSetter()));
788        }
789    
790        private static boolean isAccessorWithEmptyBody(@Nullable PropertyAccessorDescriptor accessorDescriptor) {
791            return accessorDescriptor == null || !accessorDescriptor.hasBody();
792        }
793    
794        public static Type comparisonOperandType(Type left, Type right) {
795            if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE;
796            if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE;
797            if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE;
798            return Type.INT_TYPE;
799        }
800    
801        @NotNull
802        public static Type numberFunctionOperandType(@NotNull Type expectedType) {
803            if (expectedType == Type.SHORT_TYPE || expectedType == Type.BYTE_TYPE || expectedType == Type.CHAR_TYPE) {
804                return Type.INT_TYPE;
805            }
806            return expectedType;
807        }
808    
809        public static void pop(@NotNull MethodVisitor v, @NotNull Type type) {
810            if (type.getSize() == 2) {
811                v.visitInsn(Opcodes.POP2);
812            }
813            else {
814                v.visitInsn(Opcodes.POP);
815            }
816        }
817    
818        public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) {
819            int size = type.getSize();
820            if (size == 2) {
821                v.dup2();
822            }
823            else if (size == 1) {
824                v.dup();
825            }
826            else {
827                throw new UnsupportedOperationException();
828            }
829        }
830    
831        public static void writeKotlinSyntheticClassAnnotation(@NotNull ClassBuilder v, @NotNull KotlinSyntheticClass.Kind kind) {
832            AnnotationVisitor av = v.newAnnotation(Type.getObjectType(KotlinSyntheticClass.CLASS_NAME.getInternalName()).getDescriptor(), true);
833            av.visit(ABI_VERSION_FIELD_NAME, JvmAbi.VERSION);
834            av.visitEnum(KotlinSyntheticClass.KIND_FIELD_NAME.asString(),
835                         Type.getObjectType(KotlinSyntheticClass.KIND_INTERNAL_NAME).getDescriptor(),
836                         kind.toString());
837            av.visitEnd();
838        }
839    
840        @NotNull
841        public static String asmDescByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
842            return asmTypeByFqNameWithoutInnerClasses(fqName).getDescriptor();
843        }
844    
845        @NotNull
846        public static String shortNameByAsmType(@NotNull Type type) {
847            String internalName = type.getInternalName();
848            int lastSlash = internalName.lastIndexOf('/');
849            return lastSlash < 0 ? internalName : internalName.substring(lastSlash + 1);
850        }
851    
852        @NotNull
853        public static Type asmTypeByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
854            return Type.getObjectType(internalNameByFqNameWithoutInnerClasses(fqName));
855        }
856    
857        @NotNull
858        public static String internalNameByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
859            return JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName();
860        }
861    
862        public static void writeOuterClassAndEnclosingMethod(
863                @NotNull ClassDescriptor descriptor,
864                @NotNull DeclarationDescriptor originalDescriptor,
865                @NotNull JetTypeMapper typeMapper,
866                @NotNull ClassBuilder v
867        ) {
868            String outerClassName = getOuterClassName(descriptor, originalDescriptor, typeMapper);
869    
870            FunctionDescriptor function = DescriptorUtils.getParentOfType(descriptor, FunctionDescriptor.class);
871            while (function != null && JvmCodegenUtil.isLambdaWhichWillBeInlined(typeMapper.getBindingContext(), function)) {
872                function = DescriptorUtils.getParentOfType(function, FunctionDescriptor.class);
873            }
874    
875            if (function != null) {
876                Method method = typeMapper.mapSignature(function).getAsmMethod();
877                v.visitOuterClass(outerClassName, method.getName(), method.getDescriptor());
878            }
879            else {
880                v.visitOuterClass(outerClassName, null, null);
881            }
882        }
883    
884        @NotNull
885        private static String getOuterClassName(
886                @NotNull ClassDescriptor classDescriptor,
887                @NotNull DeclarationDescriptor originalDescriptor,
888                @NotNull JetTypeMapper typeMapper
889        ) {
890            BindingContext bindingContext = typeMapper.getBindingContext();
891    
892            DeclarationDescriptor container = classDescriptor.getContainingDeclaration();
893            while (container != null) {
894                if (container instanceof ClassDescriptor) {
895                    return typeMapper.mapClass((ClassDescriptor) container).getInternalName();
896                }
897                else if (CodegenBinding.isLocalFunOrLambda(container) &&
898                         !JvmCodegenUtil.isLambdaWhichWillBeInlined(bindingContext, container)) {
899                    return asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) container).getInternalName();
900                }
901    
902                container = container.getContainingDeclaration();
903            }
904    
905            JetFile containingFile = DescriptorToSourceUtils.getContainingFile(originalDescriptor);
906            assert containingFile != null : "Containing file should be present for " + classDescriptor;
907            return PackagePartClassUtils.getPackagePartInternalName(containingFile);
908        }
909    
910        public static void putJavaLangClassInstance(@NotNull InstructionAdapter v, @NotNull Type type) {
911            if (isPrimitive(type)) {
912                v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;");
913            }
914            else {
915                v.aconst(type);
916            }
917        }
918    
919        public static int getReceiverIndex(@NotNull CodegenContext context, @NotNull CallableMemberDescriptor descriptor) {
920            OwnerKind kind = context.getContextKind();
921            //Trait always should have this descriptor
922            return kind != OwnerKind.TRAIT_IMPL && isStaticMethod(kind, descriptor) ? 0 : 1;
923        }
924    }