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