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        @NotNull
490        public static StackValue genEqualsForExpressionsOnStack(
491                @NotNull InstructionAdapter v,
492                @NotNull IElementType opToken,
493                @NotNull Type leftType,
494                @NotNull Type rightType
495        ) {
496            if (isPrimitive(leftType) && leftType == rightType) {
497                return StackValue.cmp(opToken, leftType);
498            }
499    
500            if (opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) {
501                return StackValue.cmp(opToken, leftType);
502            }
503    
504            v.invokestatic("kotlin/jvm/internal/Intrinsics", "areEqual", "(Ljava/lang/Object;Ljava/lang/Object;)Z", false);
505    
506            if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) {
507                genInvertBoolean(v);
508            }
509    
510            return StackValue.onStack(Type.BOOLEAN_TYPE);
511        }
512    
513        public static void genIncrement(Type expectedType, int myDelta, InstructionAdapter v) {
514            if (expectedType == Type.LONG_TYPE) {
515                v.lconst(myDelta);
516            }
517            else if (expectedType == Type.FLOAT_TYPE) {
518                v.fconst(myDelta);
519            }
520            else if (expectedType == Type.DOUBLE_TYPE) {
521                v.dconst(myDelta);
522            }
523            else {
524                v.iconst(myDelta);
525                v.add(Type.INT_TYPE);
526                StackValue.coerce(Type.INT_TYPE, expectedType, v);
527                return;
528            }
529            v.add(expectedType);
530        }
531    
532        public static Type genNegate(Type expectedType, InstructionAdapter v) {
533            if (expectedType == Type.BYTE_TYPE || expectedType == Type.SHORT_TYPE || expectedType == Type.CHAR_TYPE) {
534                expectedType = Type.INT_TYPE;
535            }
536            v.neg(expectedType);
537            return expectedType;
538        }
539    
540        public static void swap(InstructionAdapter v, Type stackTop, Type afterTop) {
541            if (stackTop.getSize() == 1) {
542                if (afterTop.getSize() == 1) {
543                    v.swap();
544                }
545                else {
546                    v.dupX2();
547                    v.pop();
548                }
549            }
550            else {
551                if (afterTop.getSize() == 1) {
552                    v.dup2X1();
553                }
554                else {
555                    v.dup2X2();
556                }
557                v.pop2();
558            }
559        }
560    
561        public static void genNotNullAssertionsForParameters(
562                @NotNull InstructionAdapter v,
563                @NotNull GenerationState state,
564                @NotNull FunctionDescriptor descriptor,
565                @NotNull FrameMap frameMap
566        ) {
567            if (!state.isParamAssertionsEnabled()) return;
568    
569            // Private method is not accessible from other classes, no assertions needed
570            if (getVisibilityAccessFlag(descriptor) == ACC_PRIVATE) return;
571    
572            for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) {
573                JetType type = parameter.getReturnType();
574                if (type == null || isNullableType(type)) continue;
575    
576                int index = frameMap.getIndex(parameter);
577                Type asmType = state.getTypeMapper().mapType(type);
578                if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
579                    v.load(index, asmType);
580                    v.visitLdcInsn(parameter.getName().asString());
581                    v.invokestatic("kotlin/jvm/internal/Intrinsics", "checkParameterIsNotNull",
582                                   "(Ljava/lang/Object;Ljava/lang/String;)V", false);
583                }
584            }
585        }
586    
587        public static void genNotNullAssertionForField(
588                @NotNull InstructionAdapter v,
589                @NotNull GenerationState state,
590                @NotNull PropertyDescriptor descriptor
591        ) {
592            genNotNullAssertion(v, state, descriptor, "checkFieldIsNotNull");
593        }
594    
595        public static void genNotNullAssertionForMethod(
596                @NotNull InstructionAdapter v,
597                @NotNull GenerationState state,
598                @NotNull ResolvedCall resolvedCall
599        ) {
600            CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
601            if (descriptor instanceof ConstructorDescriptor) return;
602    
603            genNotNullAssertion(v, state, descriptor, "checkReturnedValueIsNotNull");
604        }
605    
606        private static void genNotNullAssertion(
607                @NotNull InstructionAdapter v,
608                @NotNull GenerationState state,
609                @NotNull CallableDescriptor descriptor,
610                @NotNull String assertMethodToCall
611        ) {
612            // Assertions are generated elsewhere for platform types
613            if (JavaPackage.getPLATFORM_TYPES()) return;
614    
615            if (!state.isCallAssertionsEnabled()) return;
616    
617            if (!isDeclaredInJava(descriptor)) return;
618    
619            JetType type = descriptor.getReturnType();
620            if (type == null || isNullableType(TypesPackage.lowerIfFlexible(type))) return;
621    
622            Type asmType = state.getTypeMapper().mapReturnType(descriptor);
623            if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
624                v.dup();
625                v.visitLdcInsn(descriptor.getContainingDeclaration().getName().asString());
626                v.visitLdcInsn(descriptor.getName().asString());
627                v.invokestatic("kotlin/jvm/internal/Intrinsics", assertMethodToCall,
628                               "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V", false);
629            }
630        }
631    
632        @NotNull
633        public static StackValue genNotNullAssertions(
634                @NotNull GenerationState state,
635                @NotNull final StackValue stackValue,
636                @Nullable final Approximation.Info approximationInfo
637        ) {
638            if (!state.isCallAssertionsEnabled()) return stackValue;
639            if (approximationInfo == null || !TypesPackage.assertNotNull(approximationInfo)) return stackValue;
640    
641            return new StackValue(stackValue.type) {
642    
643                @Override
644                public void put(Type type, InstructionAdapter v) {
645                    stackValue.put(type, v);
646                    if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
647                        v.dup();
648                        v.visitLdcInsn(approximationInfo.getMessage());
649                        v.invokestatic("kotlin/jvm/internal/Intrinsics", "checkExpressionValueIsNotNull",
650                                       "(Ljava/lang/Object;Ljava/lang/String;)V", false);
651                    }
652                }
653            };
654        }
655    
656        private static boolean isDeclaredInJava(@NotNull CallableDescriptor callableDescriptor) {
657            CallableDescriptor descriptor = callableDescriptor;
658            while (true) {
659                if (descriptor instanceof JavaCallableMemberDescriptor) {
660                    return true;
661                }
662                CallableDescriptor original = descriptor.getOriginal();
663                if (descriptor == original) break;
664                descriptor = original;
665            }
666            return false;
667        }
668    
669        public static void pushDefaultValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
670            if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
671                v.aconst(null);
672            }
673            else {
674                pushDefaultPrimitiveValueOnStack(type, v);
675            }
676        }
677    
678        public static void pushDefaultPrimitiveValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
679            if (type.getSort() == Type.FLOAT) {
680                v.fconst(0);
681            }
682            else if (type.getSort() == Type.DOUBLE) {
683                v.dconst(0);
684            }
685            else if (type.getSort() == Type.LONG) {
686                v.lconst(0);
687            }
688            else {
689                v.iconst(0);
690            }
691        }
692    
693        public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
694            return isClassObjectWithBackingFieldsInOuter(propertyDescriptor.getContainingDeclaration());
695        }
696    
697        public static int getVisibilityForSpecialPropertyBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) {
698            boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null;
699            if (isDelegate || isExtensionProperty) {
700                return ACC_PRIVATE;
701            }
702            else {
703                return areBothAccessorDefault(propertyDescriptor)
704                       ? getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor))
705                       : ACC_PRIVATE;
706            }
707        }
708    
709        private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) {
710            if (!propertyDescriptor.isVar()) {
711                return propertyDescriptor;
712            }
713            else {
714                return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor;
715            }
716        }
717    
718        public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
719            boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null;
720            DeclarationDescriptor propertyContainer = propertyDescriptor.getContainingDeclaration();
721            return !propertyDescriptor.isVar()
722                   && !isExtensionProperty
723                   && isClassObject(propertyContainer) && isTrait(propertyContainer.getContainingDeclaration())
724                   && areBothAccessorDefault(propertyDescriptor)
725                   && getVisibilityForSpecialPropertyBackingField(propertyDescriptor, false) == ACC_PUBLIC;
726        }
727    
728        public static boolean isClassObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor classObject) {
729            DeclarationDescriptor containingClass = classObject.getContainingDeclaration();
730            return isClassObject(classObject) && (isClass(containingClass) || isEnumClass(containingClass));
731        }
732    
733        private static boolean areBothAccessorDefault(@NotNull PropertyDescriptor propertyDescriptor) {
734            return isAccessorWithEmptyBody(propertyDescriptor.getGetter())
735                   && (!propertyDescriptor.isVar() || isAccessorWithEmptyBody(propertyDescriptor.getSetter()));
736        }
737    
738        private static boolean isAccessorWithEmptyBody(@Nullable PropertyAccessorDescriptor accessorDescriptor) {
739            return accessorDescriptor == null || !accessorDescriptor.hasBody();
740        }
741    
742        public static Type comparisonOperandType(Type left, Type right) {
743            if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE;
744            if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE;
745            if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE;
746            return Type.INT_TYPE;
747        }
748    
749        @NotNull
750        public static Type numberFunctionOperandType(@NotNull Type expectedType) {
751            if (expectedType == Type.SHORT_TYPE || expectedType == Type.BYTE_TYPE) {
752                return Type.INT_TYPE;
753            }
754            return expectedType;
755        }
756    
757        public static void pop(@NotNull MethodVisitor v, @NotNull Type type) {
758            if (type.getSize() == 2) {
759                v.visitInsn(Opcodes.POP2);
760            }
761            else {
762                v.visitInsn(Opcodes.POP);
763            }
764        }
765    
766        public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) {
767            if (type.getSize() == 2) {
768                v.dup2();
769            }
770            else {
771                v.dup();
772            }
773        }
774    
775        public static void writeKotlinSyntheticClassAnnotation(@NotNull ClassBuilder v, @NotNull KotlinSyntheticClass.Kind kind) {
776            AnnotationVisitor av = v.newAnnotation(Type.getObjectType(KotlinSyntheticClass.CLASS_NAME.getInternalName()).getDescriptor(), true);
777            av.visit(ABI_VERSION_FIELD_NAME, JvmAbi.VERSION);
778            av.visitEnum(KotlinSyntheticClass.KIND_FIELD_NAME.asString(),
779                         Type.getObjectType(KotlinSyntheticClass.KIND_INTERNAL_NAME).getDescriptor(),
780                         kind.toString());
781            av.visitEnd();
782        }
783    
784        @NotNull
785        public static String asmDescByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
786            return asmTypeByFqNameWithoutInnerClasses(fqName).getDescriptor();
787        }
788    
789        @NotNull
790        public static String shortNameByAsmType(@NotNull Type type) {
791            String internalName = type.getInternalName();
792            int lastSlash = internalName.lastIndexOf('/');
793            return lastSlash < 0 ? internalName : internalName.substring(lastSlash + 1);
794        }
795    
796        @NotNull
797        public static Type asmTypeByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
798            return Type.getObjectType(internalNameByFqNameWithoutInnerClasses(fqName));
799        }
800    
801        @NotNull
802        public static String internalNameByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
803            return JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName();
804        }
805    
806        public static void writeOuterClassAndEnclosingMethod(
807                @NotNull ClassDescriptor descriptor,
808                @NotNull DeclarationDescriptor originalDescriptor,
809                @NotNull JetTypeMapper typeMapper,
810                @NotNull ClassBuilder v
811        ) {
812            String outerClassName = getOuterClassName(descriptor, originalDescriptor, typeMapper);
813            FunctionDescriptor function = DescriptorUtils.getParentOfType(descriptor, FunctionDescriptor.class);
814    
815            if (function != null) {
816                Method method = typeMapper.mapSignature(function).getAsmMethod();
817                v.visitOuterClass(outerClassName, method.getName(), method.getDescriptor());
818            }
819            else {
820                v.visitOuterClass(outerClassName, null, null);
821            }
822        }
823    
824        @NotNull
825        private static String getOuterClassName(
826                @NotNull ClassDescriptor classDescriptor,
827                @NotNull DeclarationDescriptor originalDescriptor,
828                @NotNull JetTypeMapper typeMapper
829        ) {
830            DeclarationDescriptor container = classDescriptor.getContainingDeclaration();
831            while (container != null) {
832                if (container instanceof ClassDescriptor) {
833                    return typeMapper.mapClass((ClassDescriptor) container).getInternalName();
834                }
835                else if (CodegenBinding.isLocalFunOrLambda(container)) {
836                    ClassDescriptor descriptor =
837                            CodegenBinding.anonymousClassForFunction(typeMapper.getBindingContext(), (FunctionDescriptor) container);
838                    return typeMapper.mapClass(descriptor).getInternalName();
839                }
840    
841                container = container.getContainingDeclaration();
842            }
843    
844            JetFile containingFile = DescriptorToSourceUtils.getContainingFile(originalDescriptor);
845            assert containingFile != null : "Containing file should be present for " + classDescriptor;
846            return PackagePartClassUtils.getPackagePartInternalName(containingFile);
847        }
848    
849        public static void putJavaLangClassInstance(@NotNull InstructionAdapter v, @NotNull Type type) {
850            if (isPrimitive(type)) {
851                v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;");
852            }
853            else {
854                v.aconst(type);
855            }
856        }
857    
858        public static int getReceiverIndex(@NotNull CodegenContext context, @NotNull CallableMemberDescriptor descriptor) {
859            OwnerKind kind = context.getContextKind();
860            //Trait always should have this descriptor
861            return kind != OwnerKind.TRAIT_IMPL && isStaticMethod(kind, descriptor) ? 0 : 1;
862        }
863    }