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