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