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