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