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                if (((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty().isConst()) {
292                    return ACC_DEPRECATED;
293                }
294                return KotlinBuiltIns.isDeprecated(descriptor)
295                       ? ACC_DEPRECATED
296                       : getDeprecatedAccessFlag(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty());
297            }
298            else if (KotlinBuiltIns.isDeprecated(descriptor)) {
299                return ACC_DEPRECATED;
300            }
301            return 0;
302        }
303    
304        private static int getVarargsFlag(FunctionDescriptor functionDescriptor) {
305            if (!functionDescriptor.getValueParameters().isEmpty()
306                && functionDescriptor.getValueParameters().get(functionDescriptor.getValueParameters().size() - 1)
307                           .getVarargElementType() != null) {
308                return ACC_VARARGS;
309            }
310            return 0;
311        }
312    
313        @Nullable
314        private static Integer specialCaseVisibility(@NotNull MemberDescriptor memberDescriptor) {
315            DeclarationDescriptor containingDeclaration = memberDescriptor.getContainingDeclaration();
316            Visibility memberVisibility = memberDescriptor.getVisibility();
317            if (isInterface(containingDeclaration)) {
318                return memberVisibility == Visibilities.PRIVATE ? NO_FLAG_PACKAGE_PRIVATE : ACC_PUBLIC;
319            }
320    
321            if (memberVisibility == Visibilities.LOCAL && memberDescriptor instanceof CallableMemberDescriptor) {
322                return ACC_PUBLIC;
323            }
324    
325            if (isEnumEntry(memberDescriptor)) {
326                return NO_FLAG_PACKAGE_PRIVATE;
327            }
328    
329            if (memberDescriptor instanceof ConstructorDescriptor && isAnonymousObject(memberDescriptor.getContainingDeclaration())) {
330                return NO_FLAG_PACKAGE_PRIVATE;
331            }
332    
333            if (memberDescriptor instanceof SyntheticJavaPropertyDescriptor) {
334                return getVisibilityAccessFlag(((SyntheticJavaPropertyDescriptor) memberDescriptor).getGetMethod());
335            }
336            if (memberDescriptor instanceof PropertyAccessorDescriptor) {
337                PropertyDescriptor property = ((PropertyAccessorDescriptor) memberDescriptor).getCorrespondingProperty();
338                if (property instanceof SyntheticJavaPropertyDescriptor) {
339                    FunctionDescriptor method = memberDescriptor == property.getGetter()
340                                                ? ((SyntheticJavaPropertyDescriptor) property).getGetMethod()
341                                                : ((SyntheticJavaPropertyDescriptor) property).getSetMethod();
342                    assert method != null : "No get/set method in SyntheticJavaPropertyDescriptor: " + property;
343                    return getVisibilityAccessFlag(method);
344                }
345            }
346    
347            if (memberDescriptor instanceof CallableDescriptor && memberVisibility == Visibilities.PROTECTED) {
348                for (CallableDescriptor overridden : DescriptorUtils.getAllOverriddenDescriptors((CallableDescriptor) memberDescriptor)) {
349                    if (isInterface(overridden.getContainingDeclaration())) {
350                        return ACC_PUBLIC;
351                    }
352                }
353            }
354    
355            if (!Visibilities.isPrivate(memberVisibility)) {
356                return null;
357            }
358    
359            // the following code is only for PRIVATE visibility of member
360            if (memberDescriptor instanceof ConstructorDescriptor) {
361                if (isNonCompanionObject(containingDeclaration) || isEnumEntry(containingDeclaration)) {
362                    return NO_FLAG_PACKAGE_PRIVATE;
363                }
364                if (isEnumClass(containingDeclaration)) {
365                    //TODO: should be ACC_PRIVATE
366                    // see http://youtrack.jetbrains.com/issue/KT-2680
367                    return ACC_PROTECTED;
368                }
369            }
370    
371            if (memberDescriptor instanceof PropertyDescriptor && ((PropertyDescriptor) memberDescriptor).isConst()) return null;
372    
373            if (containingDeclaration instanceof PackageFragmentDescriptor) {
374                return ACC_PUBLIC;
375            }
376            return null;
377        }
378    
379        public static Type stringValueOfType(Type type) {
380            int sort = type.getSort();
381            return sort == Type.OBJECT || sort == Type.ARRAY
382                   ? OBJECT_TYPE
383                   : sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type;
384        }
385    
386        private static Type stringBuilderAppendType(Type type) {
387            switch (type.getSort()) {
388                case Type.OBJECT:
389                    return STRING_BUILDER_OBJECT_APPEND_ARG_TYPES.contains(type) ? type : OBJECT_TYPE;
390                case Type.ARRAY:
391                    return OBJECT_TYPE;
392                case Type.BYTE:
393                case Type.SHORT:
394                    return Type.INT_TYPE;
395                default:
396                    return type;
397            }
398        }
399    
400        public static void genThrow(@NotNull InstructionAdapter v, @NotNull String exception, @Nullable String message) {
401            v.anew(Type.getObjectType(exception));
402            v.dup();
403            if (message != null) {
404                v.aconst(message);
405                v.invokespecial(exception, "<init>", "(Ljava/lang/String;)V", false);
406            }
407            else {
408                v.invokespecial(exception, "<init>", "()V", false);
409            }
410            v.athrow();
411        }
412    
413        public static void genClosureFields(CalculatedClosure closure, ClassBuilder v, JetTypeMapper typeMapper) {
414            List<Pair<String, Type>> allFields = new ArrayList<Pair<String, Type>>();
415    
416            ClassifierDescriptor captureThis = closure.getCaptureThis();
417            if (captureThis != null) {
418                allFields.add(Pair.create(CAPTURED_THIS_FIELD, typeMapper.mapType(captureThis)));
419            }
420    
421            JetType captureReceiverType = closure.getCaptureReceiverType();
422            if (captureReceiverType != null) {
423                allFields.add(Pair.create(CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiverType)));
424            }
425    
426            allFields.addAll(closure.getRecordedFields());
427            genClosureFields(allFields, v);
428        }
429    
430        public static void genClosureFields(List<Pair<String, Type>> allFields, ClassBuilder builder) {
431            //noinspection PointlessBitwiseExpression
432            int access = NO_FLAG_PACKAGE_PRIVATE | ACC_SYNTHETIC | ACC_FINAL;
433            for (Pair<String, Type> field : allFields) {
434                builder.newField(JvmDeclarationOrigin.NO_ORIGIN, access, field.first, field.second.getDescriptor(), null, null);
435            }
436        }
437    
438        public static List<FieldInfo> transformCapturedParams(List<Pair<String, Type>> allFields, Type owner) {
439            List<FieldInfo> result = new ArrayList<FieldInfo>();
440            for (Pair<String, Type> field : allFields) {
441                result.add(FieldInfo.createForHiddenField(owner, field.second, field.first));
442            }
443            return result;
444        }
445    
446        public static int genAssignInstanceFieldFromParam(FieldInfo info, int index, InstructionAdapter iv) {
447            assert !info.isStatic();
448            Type fieldType = info.getFieldType();
449            iv.load(0, info.getOwnerType());//this
450            iv.load(index, fieldType); //param
451            iv.visitFieldInsn(PUTFIELD, info.getOwnerInternalName(), info.getFieldName(), fieldType.getDescriptor());
452            index += fieldType.getSize();
453            return index;
454        }
455    
456        public static void genStringBuilderConstructor(InstructionAdapter v) {
457            v.visitTypeInsn(NEW, "java/lang/StringBuilder");
458            v.dup();
459            v.invokespecial("java/lang/StringBuilder", "<init>", "()V", false);
460        }
461    
462        public static void genInvokeAppendMethod(InstructionAdapter v, Type type) {
463            type = stringBuilderAppendType(type);
464            v.invokevirtual("java/lang/StringBuilder", "append", "(" + type.getDescriptor() + ")Ljava/lang/StringBuilder;", false);
465        }
466    
467        public static StackValue genToString(final StackValue receiver, final Type receiverType) {
468            return StackValue.operation(JAVA_STRING_TYPE, new Function1<InstructionAdapter, Unit>() {
469                @Override
470                public Unit invoke(InstructionAdapter v) {
471                    Type type = stringValueOfType(receiverType);
472                    receiver.put(type, v);
473                    v.invokestatic("java/lang/String", "valueOf", "(" + type.getDescriptor() + ")Ljava/lang/String;", false);
474                    return null;
475                }
476            });
477        }
478    
479        static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type) {
480            if (type.getSort() == Type.ARRAY) {
481                Type elementType = correctElementType(type);
482                if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
483                    iv.invokestatic("java/util/Arrays", "hashCode", "([Ljava/lang/Object;)I", false);
484                }
485                else {
486                    iv.invokestatic("java/util/Arrays", "hashCode", "(" + type.getDescriptor() + ")I", false);
487                }
488            }
489            else if (type.getSort() == Type.OBJECT) {
490                iv.invokevirtual("java/lang/Object", "hashCode", "()I", false);
491            }
492            else if (type.getSort() == Type.LONG) {
493                genLongHashCode(mv, iv);
494            }
495            else if (type.getSort() == Type.DOUBLE) {
496                iv.invokestatic("java/lang/Double", "doubleToLongBits", "(D)J", false);
497                genLongHashCode(mv, iv);
498            }
499            else if (type.getSort() == Type.FLOAT) {
500                iv.invokestatic("java/lang/Float", "floatToIntBits", "(F)I", false);
501            }
502            else if (type.getSort() == Type.BOOLEAN) {
503                Label end = new Label();
504                iv.dup();
505                iv.ifeq(end);
506                iv.pop();
507                iv.iconst(1);
508                iv.mark(end);
509            }
510            else { // byte short char int
511                // do nothing
512            }
513        }
514    
515        private static void genLongHashCode(MethodVisitor mv, InstructionAdapter iv) {
516            iv.dup2();
517            iv.iconst(32);
518            iv.ushr(Type.LONG_TYPE);
519            iv.xor(Type.LONG_TYPE);
520            mv.visitInsn(L2I);
521        }
522    
523        static void genInvertBoolean(InstructionAdapter v) {
524            v.iconst(1);
525            v.xor(Type.INT_TYPE);
526        }
527    
528        @NotNull
529        public static StackValue genEqualsForExpressionsOnStack(
530                final @NotNull IElementType opToken,
531                final @NotNull StackValue left,
532                final @NotNull StackValue right
533        ) {
534            final Type leftType = left.type;
535            final Type rightType = right.type;
536            if (isPrimitive(leftType) && leftType == rightType) {
537                return StackValue.cmp(opToken, leftType, left, right);
538            }
539    
540            return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() {
541                @Override
542                public Unit invoke(InstructionAdapter v) {
543                    left.put(leftType, v);
544                    right.put(rightType, v);
545                    genAreEqualCall(v);
546    
547                    if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) {
548                        genInvertBoolean(v);
549                    }
550                    return Unit.INSTANCE$;
551                }
552            });
553        }
554    
555        public static void genAreEqualCall(InstructionAdapter v) {
556            v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "areEqual", "(Ljava/lang/Object;Ljava/lang/Object;)Z", false);
557        }
558    
559        public static void genIncrement(Type expectedType, int myDelta, InstructionAdapter v) {
560            if (expectedType == Type.LONG_TYPE) {
561                v.lconst(myDelta);
562            }
563            else if (expectedType == Type.FLOAT_TYPE) {
564                v.fconst(myDelta);
565            }
566            else if (expectedType == Type.DOUBLE_TYPE) {
567                v.dconst(myDelta);
568            }
569            else {
570                v.iconst(myDelta);
571                v.add(Type.INT_TYPE);
572                StackValue.coerce(Type.INT_TYPE, expectedType, v);
573                return;
574            }
575            v.add(expectedType);
576        }
577    
578        public static void swap(InstructionAdapter v, Type stackTop, Type afterTop) {
579            if (stackTop.getSize() == 1) {
580                if (afterTop.getSize() == 1) {
581                    v.swap();
582                }
583                else {
584                    v.dupX2();
585                    v.pop();
586                }
587            }
588            else {
589                if (afterTop.getSize() == 1) {
590                    v.dup2X1();
591                }
592                else {
593                    v.dup2X2();
594                }
595                v.pop2();
596            }
597        }
598    
599        public static void genNotNullAssertionsForParameters(
600                @NotNull InstructionAdapter v,
601                @NotNull GenerationState state,
602                @NotNull FunctionDescriptor descriptor,
603                @NotNull FrameMap frameMap
604        ) {
605            if (!state.isParamAssertionsEnabled()) return;
606    
607            // Private method is not accessible from other classes, no assertions needed
608            if (getVisibilityAccessFlag(descriptor) == ACC_PRIVATE) return;
609    
610            ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
611            if (receiverParameter != null) {
612                genParamAssertion(v, state.getTypeMapper(), frameMap, receiverParameter, "$receiver");
613            }
614    
615            for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) {
616                genParamAssertion(v, state.getTypeMapper(), frameMap, parameter, parameter.getName().asString());
617            }
618        }
619    
620        private static void genParamAssertion(
621                @NotNull InstructionAdapter v,
622                @NotNull JetTypeMapper typeMapper,
623                @NotNull FrameMap frameMap,
624                @NotNull CallableDescriptor parameter,
625                @NotNull String name
626        ) {
627            JetType type = parameter.getReturnType();
628            if (type == null || isNullableType(type)) return;
629            
630            int index = frameMap.getIndex(parameter);
631            Type asmType = typeMapper.mapType(type);
632            if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
633                v.load(index, asmType);
634                v.visitLdcInsn(name);
635                v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "checkParameterIsNotNull",
636                               "(Ljava/lang/Object;Ljava/lang/String;)V", false);
637            }
638        }
639    
640        public static boolean genNotNullAssertionForField(
641                @NotNull InstructionAdapter v,
642                @NotNull GenerationState state,
643                @NotNull PropertyDescriptor descriptor
644        ) {
645            return genNotNullAssertion(v, state, descriptor, "checkFieldIsNotNull");
646        }
647    
648        private static boolean genNotNullAssertion(
649                @NotNull InstructionAdapter v,
650                @NotNull GenerationState state,
651                @NotNull CallableDescriptor descriptor,
652                @NotNull String assertMethodToCall
653        ) {
654            // Assertions are generated elsewhere for platform types
655            if (JvmPackage.getPLATFORM_TYPES()) return false;
656    
657            if (!state.isCallAssertionsEnabled()) return false;
658    
659            if (!isDeclaredInJava(descriptor)) return false;
660    
661            JetType type = descriptor.getReturnType();
662            if (type == null || isNullableType(TypesPackage.lowerIfFlexible(type))) return false;
663    
664            Type asmType = state.getTypeMapper().mapReturnType(descriptor);
665            if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
666                v.dup();
667                v.visitLdcInsn(descriptor.getContainingDeclaration().getName().asString());
668                v.visitLdcInsn(descriptor.getName().asString());
669                v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, assertMethodToCall,
670                               "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V", false);
671                return true;
672            }
673    
674            return false;
675        }
676    
677        @NotNull
678        public static StackValue genNotNullAssertions(
679                @NotNull GenerationState state,
680                @NotNull final StackValue stackValue,
681                @Nullable final RuntimeAssertionInfo runtimeAssertionInfo
682        ) {
683            if (!state.isCallAssertionsEnabled()) return stackValue;
684            if (runtimeAssertionInfo == null || !runtimeAssertionInfo.getNeedNotNullAssertion()) return stackValue;
685    
686            return new StackValue(stackValue.type) {
687    
688                @Override
689                public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
690                    stackValue.put(type, v);
691                    if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
692                        v.dup();
693                        v.visitLdcInsn(runtimeAssertionInfo.getMessage());
694                        v.invokestatic("kotlin/jvm/internal/Intrinsics", "checkExpressionValueIsNotNull",
695                                       "(Ljava/lang/Object;Ljava/lang/String;)V", false);
696                    }
697                }
698            };
699        }
700    
701        private static boolean isDeclaredInJava(@NotNull CallableDescriptor callableDescriptor) {
702            CallableDescriptor descriptor = callableDescriptor;
703            while (true) {
704                if (descriptor instanceof JavaCallableMemberDescriptor) {
705                    return true;
706                }
707                CallableDescriptor original = descriptor.getOriginal();
708                if (descriptor == original) break;
709                descriptor = original;
710            }
711            return false;
712        }
713    
714        public static void pushDefaultValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
715            if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
716                v.aconst(null);
717            }
718            else {
719                pushDefaultPrimitiveValueOnStack(type, v);
720            }
721        }
722    
723        public static void pushDefaultPrimitiveValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
724            if (type.getSort() == Type.FLOAT) {
725                v.fconst(0);
726            }
727            else if (type.getSort() == Type.DOUBLE) {
728                v.dconst(0);
729            }
730            else if (type.getSort() == Type.LONG) {
731                v.lconst(0);
732            }
733            else {
734                v.iconst(0);
735            }
736        }
737    
738        public static boolean isInstancePropertyWithStaticBackingField(@NotNull PropertyDescriptor propertyDescriptor) {
739            if (propertyDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
740                return false;
741            }
742    
743            return isNonCompanionObject(propertyDescriptor.getContainingDeclaration()) || isPropertyWithBackingFieldInOuterClass(propertyDescriptor);
744        }
745    
746        public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
747            return propertyDescriptor.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE &&
748                   isCompanionObjectWithBackingFieldsInOuter(propertyDescriptor.getContainingDeclaration());
749        }
750    
751        public static int getVisibilityForSpecialPropertyBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) {
752            boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null;
753            if (isDelegate || isExtensionProperty) {
754                return ACC_PRIVATE;
755            }
756            else {
757                return areBothAccessorDefault(propertyDescriptor)
758                       ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor))
759                       : ACC_PRIVATE;
760            }
761        }
762    
763        private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) {
764            if (!propertyDescriptor.isVar()) {
765                return propertyDescriptor;
766            }
767            else {
768                return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor;
769            }
770        }
771    
772        public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
773            boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null;
774            DeclarationDescriptor propertyContainer = propertyDescriptor.getContainingDeclaration();
775            return !propertyDescriptor.isVar()
776                   && !isExtensionProperty
777                   && isCompanionObject(propertyContainer) && isTrait(propertyContainer.getContainingDeclaration())
778                   && areBothAccessorDefault(propertyDescriptor)
779                   && getVisibilityForSpecialPropertyBackingField(propertyDescriptor, false) == ACC_PUBLIC;
780        }
781    
782        public static boolean isCompanionObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor companionObject) {
783            DeclarationDescriptor containingClass = companionObject.getContainingDeclaration();
784            return isCompanionObject(companionObject) && (isClass(containingClass) || isEnumClass(containingClass));
785        }
786    
787        private static boolean areBothAccessorDefault(@NotNull PropertyDescriptor propertyDescriptor) {
788            return isAccessorWithEmptyBody(propertyDescriptor.getGetter())
789                   && (!propertyDescriptor.isVar() || isAccessorWithEmptyBody(propertyDescriptor.getSetter()));
790        }
791    
792        private static boolean isAccessorWithEmptyBody(@Nullable PropertyAccessorDescriptor accessorDescriptor) {
793            return accessorDescriptor == null || !accessorDescriptor.hasBody();
794        }
795    
796        public static Type comparisonOperandType(Type left, Type right) {
797            if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE;
798            if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE;
799            if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE;
800            return Type.INT_TYPE;
801        }
802    
803        @NotNull
804        public static Type numberFunctionOperandType(@NotNull Type expectedType) {
805            if (expectedType == Type.SHORT_TYPE || expectedType == Type.BYTE_TYPE || expectedType == Type.CHAR_TYPE) {
806                return Type.INT_TYPE;
807            }
808            return expectedType;
809        }
810    
811        public static void pop(@NotNull MethodVisitor v, @NotNull Type type) {
812            if (type.getSize() == 2) {
813                v.visitInsn(Opcodes.POP2);
814            }
815            else {
816                v.visitInsn(Opcodes.POP);
817            }
818        }
819    
820        public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) {
821            int size = type.getSize();
822            if (size == 2) {
823                v.dup2();
824            }
825            else if (size == 1) {
826                v.dup();
827            }
828            else {
829                throw new UnsupportedOperationException();
830            }
831        }
832    
833        public static void writeKotlinSyntheticClassAnnotation(@NotNull ClassBuilder v, @NotNull KotlinSyntheticClass.Kind kind) {
834            AnnotationVisitor av = v.newAnnotation(Type.getObjectType(KotlinSyntheticClass.CLASS_NAME.getInternalName()).getDescriptor(), true);
835            JvmCodegenUtil.writeAbiVersion(av);
836            av.visitEnum(
837                    JvmAnnotationNames.KIND_FIELD_NAME,
838                    Type.getObjectType(KotlinSyntheticClass.KIND_INTERNAL_NAME).getDescriptor(),
839                    kind.toString()
840            );
841            av.visitEnd();
842        }
843    
844        @NotNull
845        public static String asmDescByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
846            return asmTypeByFqNameWithoutInnerClasses(fqName).getDescriptor();
847        }
848    
849        @NotNull
850        public static String shortNameByAsmType(@NotNull Type type) {
851            String internalName = type.getInternalName();
852            int lastSlash = internalName.lastIndexOf('/');
853            return lastSlash < 0 ? internalName : internalName.substring(lastSlash + 1);
854        }
855    
856        @NotNull
857        public static Type asmTypeByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
858            return Type.getObjectType(internalNameByFqNameWithoutInnerClasses(fqName));
859        }
860    
861        @NotNull
862        public static String internalNameByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
863            return JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName();
864        }
865    
866        public static void putJavaLangClassInstance(@NotNull InstructionAdapter v, @NotNull Type type) {
867            if (isPrimitive(type)) {
868                v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;");
869            }
870            else {
871                v.aconst(type);
872            }
873        }
874    
875        public static void wrapJavaClassIntoKClass(@NotNull InstructionAdapter v) {
876            v.invokestatic(REFLECTION, "foreignKotlinClass", Type.getMethodDescriptor(K_CLASS_TYPE, getType(Class.class)), false);
877        }
878    
879    
880        public static void wrapJavaClassesIntoKClasses(@NotNull InstructionAdapter v) {
881            v.invokestatic(REFLECTION, "foreignKotlinClasses", Type.getMethodDescriptor(K_CLASS_ARRAY_TYPE, getType(Class[].class)), false);
882        }
883    
884        public static int getReceiverIndex(@NotNull CodegenContext context, @NotNull CallableMemberDescriptor descriptor) {
885            OwnerKind kind = context.getContextKind();
886            //Trait always should have this descriptor
887            return kind != OwnerKind.TRAIT_IMPL && isStaticMethod(kind, descriptor) ? 0 : 1;
888        }
889    }