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