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