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