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