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