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