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