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