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.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.*;
054    import static org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
055    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
056    import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE;
057    import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.getType;
058    import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.ABI_VERSION_FIELD_NAME;
059    import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass;
060    import static org.jetbrains.jet.lang.resolve.java.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        @NotNull
323        public static Type getTraitImplThisParameterType(@NotNull ClassDescriptor traitDescriptor, @NotNull JetTypeMapper typeMapper) {
324            JetType jetType = getSuperClass(traitDescriptor);
325            Type type = typeMapper.mapType(jetType);
326            if (type.getInternalName().equals("java/lang/Object")) {
327                return typeMapper.mapType(traitDescriptor.getDefaultType());
328            }
329            return type;
330        }
331    
332        private static Type stringValueOfType(Type type) {
333            int sort = type.getSort();
334            return sort == Type.OBJECT || sort == Type.ARRAY
335                   ? AsmTypeConstants.OBJECT_TYPE
336                   : sort == Type.BYTE || sort == Type.SHORT ? Type.INT_TYPE : type;
337        }
338    
339        private static Type stringBuilderAppendType(Type type) {
340            switch (type.getSort()) {
341                case Type.OBJECT:
342                    return STRING_BUILDER_OBJECT_APPEND_ARG_TYPES.contains(type) ? type : AsmTypeConstants.OBJECT_TYPE;
343                case Type.ARRAY:
344                    return AsmTypeConstants.OBJECT_TYPE;
345                case Type.BYTE:
346                case Type.SHORT:
347                    return Type.INT_TYPE;
348                default:
349                    return type;
350            }
351        }
352    
353        public static void genThrow(@NotNull MethodVisitor mv, @NotNull String exception, @NotNull String message) {
354            InstructionAdapter iv = new InstructionAdapter(mv);
355            iv.anew(Type.getObjectType(exception));
356            iv.dup();
357            iv.aconst(message);
358            iv.invokespecial(exception, "<init>", "(Ljava/lang/String;)V");
359            iv.athrow();
360        }
361    
362        public static void genClosureFields(CalculatedClosure closure, ClassBuilder v, JetTypeMapper typeMapper) {
363            List<Pair<String, Type>> allFields = new ArrayList<Pair<String, Type>>();
364    
365            ClassifierDescriptor captureThis = closure.getCaptureThis();
366            if (captureThis != null) {
367                allFields.add(Pair.create(CAPTURED_THIS_FIELD, typeMapper.mapType(captureThis)));
368            }
369    
370            JetType captureReceiverType = closure.getCaptureReceiverType();
371            if (captureReceiverType != null) {
372                allFields.add(Pair.create(CAPTURED_RECEIVER_FIELD, typeMapper.mapType(captureReceiverType)));
373            }
374    
375            allFields.addAll(closure.getRecordedFields());
376            genClosureFields(allFields, v);
377        }
378    
379        public static void genClosureFields(List<Pair<String, Type>> allFields, ClassBuilder builder) {
380            //noinspection PointlessBitwiseExpression
381            int access = NO_FLAG_PACKAGE_PRIVATE | ACC_SYNTHETIC | ACC_FINAL;
382            for (Pair<String, Type> field : allFields) {
383                builder.newField(NO_ORIGIN, access, field.first, field.second.getDescriptor(), null, null);
384            }
385        }
386    
387        public static List<FieldInfo> transformCapturedParams(List<Pair<String, Type>> allFields, Type owner) {
388            List<FieldInfo> result = new ArrayList<FieldInfo>();
389            for (Pair<String, Type> field : allFields) {
390                result.add(FieldInfo.createForHiddenField(owner, field.second, field.first));
391            }
392            return result;
393        }
394    
395        public static int genAssignInstanceFieldFromParam(FieldInfo info, int index, InstructionAdapter iv) {
396            assert !info.isStatic();
397            Type fieldType = info.getFieldType();
398            iv.load(0, info.getOwnerType());//this
399            iv.load(index, fieldType); //param
400            iv.visitFieldInsn(PUTFIELD, info.getOwnerInternalName(), info.getFieldName(), fieldType.getDescriptor());
401            index += fieldType.getSize();
402            return index;
403        }
404    
405        public static void genStringBuilderConstructor(InstructionAdapter v) {
406            v.visitTypeInsn(NEW, "java/lang/StringBuilder");
407            v.dup();
408            v.invokespecial("java/lang/StringBuilder", "<init>", "()V");
409        }
410    
411        public static void genInvokeAppendMethod(InstructionAdapter v, Type type) {
412            type = stringBuilderAppendType(type);
413            v.invokevirtual("java/lang/StringBuilder", "append", "(" + type.getDescriptor() + ")Ljava/lang/StringBuilder;");
414        }
415    
416        public static StackValue genToString(InstructionAdapter v, StackValue receiver, Type receiverType) {
417            Type type = stringValueOfType(receiverType);
418            receiver.put(type, v);
419            v.invokestatic("java/lang/String", "valueOf", "(" + type.getDescriptor() + ")Ljava/lang/String;");
420            return StackValue.onStack(JAVA_STRING_TYPE);
421        }
422    
423        static void genHashCode(MethodVisitor mv, InstructionAdapter iv, Type type) {
424            if (type.getSort() == Type.ARRAY) {
425                Type elementType = correctElementType(type);
426                if (elementType.getSort() == Type.OBJECT || elementType.getSort() == Type.ARRAY) {
427                    iv.invokestatic("java/util/Arrays", "hashCode", "([Ljava/lang/Object;)I");
428                }
429                else {
430                    iv.invokestatic("java/util/Arrays", "hashCode", "(" + type.getDescriptor() + ")I");
431                }
432            }
433            else if (type.getSort() == Type.OBJECT) {
434                iv.invokevirtual("java/lang/Object", "hashCode", "()I");
435            }
436            else if (type.getSort() == Type.LONG) {
437                genLongHashCode(mv, iv);
438            }
439            else if (type.getSort() == Type.DOUBLE) {
440                iv.invokestatic("java/lang/Double", "doubleToLongBits", "(D)J");
441                genLongHashCode(mv, iv);
442            }
443            else if (type.getSort() == Type.FLOAT) {
444                iv.invokestatic("java/lang/Float", "floatToIntBits", "(F)I");
445            }
446            else if (type.getSort() == Type.BOOLEAN) {
447                Label end = new Label();
448                iv.dup();
449                iv.ifeq(end);
450                iv.pop();
451                iv.iconst(1);
452                iv.mark(end);
453            }
454            else { // byte short char int
455                // do nothing
456            }
457        }
458    
459        private static void genLongHashCode(MethodVisitor mv, InstructionAdapter iv) {
460            iv.dup2();
461            iv.iconst(32);
462            iv.ushr(Type.LONG_TYPE);
463            iv.xor(Type.LONG_TYPE);
464            mv.visitInsn(L2I);
465        }
466    
467        static void genInvertBoolean(InstructionAdapter v) {
468            v.iconst(1);
469            v.xor(Type.INT_TYPE);
470        }
471    
472        public static StackValue genEqualsForExpressionsOnStack(
473                InstructionAdapter v,
474                IElementType opToken,
475                Type leftType,
476                Type rightType
477        ) {
478            if ((isNumberPrimitive(leftType) || leftType.getSort() == Type.BOOLEAN) && leftType == rightType) {
479                return StackValue.cmp(opToken, leftType);
480            }
481            else {
482                if (opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) {
483                    return StackValue.cmp(opToken, leftType);
484                }
485                else {
486                    v.invokestatic("kotlin/jvm/internal/Intrinsics", "areEqual", "(Ljava/lang/Object;Ljava/lang/Object;)Z");
487    
488                    if (opToken == JetTokens.EXCLEQ || opToken == JetTokens.EXCLEQEQEQ) {
489                        genInvertBoolean(v);
490                    }
491    
492                    return StackValue.onStack(Type.BOOLEAN_TYPE);
493                }
494            }
495        }
496    
497        public static void genIncrement(Type expectedType, int myDelta, InstructionAdapter v) {
498            if (expectedType == Type.LONG_TYPE) {
499                v.lconst(myDelta);
500            }
501            else if (expectedType == Type.FLOAT_TYPE) {
502                v.fconst(myDelta);
503            }
504            else if (expectedType == Type.DOUBLE_TYPE) {
505                v.dconst(myDelta);
506            }
507            else {
508                v.iconst(myDelta);
509                v.add(Type.INT_TYPE);
510                StackValue.coerce(Type.INT_TYPE, expectedType, v);
511                return;
512            }
513            v.add(expectedType);
514        }
515    
516        public static Type genNegate(Type expectedType, InstructionAdapter v) {
517            if (expectedType == Type.BYTE_TYPE || expectedType == Type.SHORT_TYPE || expectedType == Type.CHAR_TYPE) {
518                expectedType = Type.INT_TYPE;
519            }
520            v.neg(expectedType);
521            return expectedType;
522        }
523    
524        public static void swap(InstructionAdapter v, Type stackTop, Type afterTop) {
525            if (stackTop.getSize() == 1) {
526                if (afterTop.getSize() == 1) {
527                    v.swap();
528                } else {
529                    v.dupX2();
530                    v.pop();
531                }
532            } else {
533                if (afterTop.getSize() == 1) {
534                    v.dup2X1();
535                } else {
536                    v.dup2X2();
537                }
538                v.pop2();
539            }
540        }
541    
542        public static void genNotNullAssertionsForParameters(
543                @NotNull InstructionAdapter v,
544                @NotNull GenerationState state,
545                @NotNull FunctionDescriptor descriptor,
546                @NotNull FrameMap frameMap
547        ) {
548            if (!state.isGenerateNotNullParamAssertions()) return;
549    
550            // Private method is not accessible from other classes, no assertions needed
551            if (getVisibilityAccessFlag(descriptor) == ACC_PRIVATE) return;
552    
553            for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) {
554                JetType type = parameter.getReturnType();
555                if (type == null || isNullableType(type)) continue;
556    
557                int index = frameMap.getIndex(parameter);
558                Type asmType = state.getTypeMapper().mapType(type);
559                if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
560                    v.load(index, asmType);
561                    v.visitLdcInsn(parameter.getName().asString());
562                    v.invokestatic("kotlin/jvm/internal/Intrinsics", "checkParameterIsNotNull", "(Ljava/lang/Object;Ljava/lang/String;)V");
563                }
564            }
565        }
566    
567        public static void genNotNullAssertionForField(
568                @NotNull InstructionAdapter v,
569                @NotNull GenerationState state,
570                @NotNull PropertyDescriptor descriptor
571        ) {
572            genNotNullAssertion(v, state, descriptor, "checkFieldIsNotNull");
573        }
574    
575        public static void genNotNullAssertionForMethod(
576                @NotNull InstructionAdapter v,
577                @NotNull GenerationState state,
578                @NotNull ResolvedCall resolvedCall
579        ) {
580            CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
581            if (descriptor instanceof ConstructorDescriptor) return;
582    
583            genNotNullAssertion(v, state, descriptor, "checkReturnedValueIsNotNull");
584        }
585    
586        private static void genNotNullAssertion(
587                @NotNull InstructionAdapter v,
588                @NotNull GenerationState state,
589                @NotNull CallableDescriptor descriptor,
590                @NotNull String assertMethodToCall
591        ) {
592            if (!state.isGenerateNotNullAssertions()) return;
593    
594            if (!isDeclaredInJava(descriptor)) return;
595    
596            JetType type = descriptor.getReturnType();
597            if (type == null || isNullableType(type)) return;
598    
599            Type asmType = state.getTypeMapper().mapReturnType(descriptor);
600            if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) {
601                v.dup();
602                v.visitLdcInsn(descriptor.getContainingDeclaration().getName().asString());
603                v.visitLdcInsn(descriptor.getName().asString());
604                v.invokestatic("kotlin/jvm/internal/Intrinsics", assertMethodToCall, "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V");
605            }
606        }
607    
608        private static boolean isDeclaredInJava(@NotNull CallableDescriptor callableDescriptor) {
609            CallableDescriptor descriptor = callableDescriptor;
610            while (true) {
611                if (descriptor instanceof JavaCallableMemberDescriptor) {
612                    return true;
613                }
614                CallableDescriptor original = descriptor.getOriginal();
615                if (descriptor == original) break;
616                descriptor = original;
617            }
618            return false;
619        }
620    
621        public static void pushDefaultValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
622            if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
623                v.aconst(null);
624            }
625            else {
626                pushDefaultPrimitiveValueOnStack(type, v);
627            }
628        }
629    
630        public static void pushDefaultPrimitiveValueOnStack(@NotNull Type type, @NotNull InstructionAdapter v) {
631            if (type.getSort() == Type.FLOAT) {
632                v.fconst(0);
633            }
634            else if (type.getSort() == Type.DOUBLE) {
635                v.dconst(0);
636            }
637            else if (type.getSort() == Type.LONG) {
638                v.lconst(0);
639            }
640            else {
641                v.iconst(0);
642            }
643        }
644    
645        public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
646            return isPropertyWithSpecialBackingField(propertyDescriptor.getContainingDeclaration(), ClassKind.CLASS);
647        }
648    
649        public static int getVisibilityForSpecialPropertyBackingField(@NotNull PropertyDescriptor propertyDescriptor, boolean isDelegate) {
650            boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null;
651            if (isDelegate || isExtensionProperty) {
652                return ACC_PRIVATE;
653            } else {
654                return areBothAccessorDefault(propertyDescriptor) ?  getVisibilityAccessFlag(descriptorForVisibility(propertyDescriptor)) : ACC_PRIVATE;
655            }
656        }
657    
658        private static MemberDescriptor descriptorForVisibility(@NotNull PropertyDescriptor propertyDescriptor) {
659            if (!propertyDescriptor.isVar() ) {
660                return propertyDescriptor;
661            } else {
662                return propertyDescriptor.getSetter() != null ? propertyDescriptor.getSetter() : propertyDescriptor;
663            }
664        }
665    
666        public static boolean isPropertyWithBackingFieldCopyInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
667            boolean isExtensionProperty = propertyDescriptor.getReceiverParameter() != null;
668            return !propertyDescriptor.isVar() && !isExtensionProperty
669                   && isPropertyWithSpecialBackingField(propertyDescriptor.getContainingDeclaration(), ClassKind.TRAIT)
670                   && areBothAccessorDefault(propertyDescriptor)
671                   && getVisibilityForSpecialPropertyBackingField(propertyDescriptor, false) == ACC_PUBLIC;
672        }
673    
674        public static boolean isClassObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor classObject) {
675            return isPropertyWithSpecialBackingField(classObject, ClassKind.CLASS);
676        }
677    
678        private static boolean areBothAccessorDefault(@NotNull PropertyDescriptor propertyDescriptor) {
679            return isAccessorWithEmptyBody(propertyDescriptor.getGetter())
680                   && (!propertyDescriptor.isVar() || isAccessorWithEmptyBody(propertyDescriptor.getSetter()));
681        }
682    
683        private static boolean isAccessorWithEmptyBody(@Nullable PropertyAccessorDescriptor accessorDescriptor) {
684            return accessorDescriptor == null || !accessorDescriptor.hasBody();
685        }
686    
687        private static boolean isPropertyWithSpecialBackingField(@NotNull DeclarationDescriptor classObject, ClassKind kind) {
688            return isClassObject(classObject) && isKindOf(classObject.getContainingDeclaration(), kind);
689        }
690    
691        public static Type comparisonOperandType(Type left, Type right) {
692            if (left == Type.DOUBLE_TYPE || right == Type.DOUBLE_TYPE) return Type.DOUBLE_TYPE;
693            if (left == Type.FLOAT_TYPE || right == Type.FLOAT_TYPE) return Type.FLOAT_TYPE;
694            if (left == Type.LONG_TYPE || right == Type.LONG_TYPE) return Type.LONG_TYPE;
695            return Type.INT_TYPE;
696        }
697    
698        @NotNull
699        public static Type numberFunctionOperandType(@NotNull Type expectedType) {
700            if (expectedType == Type.SHORT_TYPE || expectedType == Type.BYTE_TYPE) {
701                return Type.INT_TYPE;
702            }
703            return expectedType;
704        }
705    
706        public static void pop(@NotNull InstructionAdapter v, @NotNull Type type) {
707            if (type.getSize() == 2) {
708                v.pop2();
709            }
710            else {
711                v.pop();
712            }
713        }
714    
715        public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) {
716            if (type.getSize() == 2) {
717                v.dup2();
718            }
719            else {
720                v.dup();
721            }
722        }
723    
724        public static void writeKotlinSyntheticClassAnnotation(@NotNull ClassBuilder v, @NotNull KotlinSyntheticClass.Kind kind) {
725            AnnotationVisitor av = v.newAnnotation(Type.getObjectType(KotlinSyntheticClass.CLASS_NAME.getInternalName()).getDescriptor(), true);
726            av.visit(ABI_VERSION_FIELD_NAME, JvmAbi.VERSION);
727            av.visitEnum(KotlinSyntheticClass.KIND_FIELD_NAME.asString(),
728                         Type.getObjectType(KotlinSyntheticClass.KIND_INTERNAL_NAME).getDescriptor(),
729                         kind.toString());
730            av.visitEnd();
731        }
732    
733        @NotNull
734        public static String asmDescByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
735            return asmTypeByFqNameWithoutInnerClasses(fqName).getDescriptor();
736        }
737    
738        @NotNull
739        public static String shortNameByAsmType(@NotNull Type type) {
740            String internalName = type.getInternalName();
741            int lastSlash = internalName.lastIndexOf('/');
742            return lastSlash < 0 ? internalName : internalName.substring(lastSlash + 1);
743        }
744    
745        @NotNull
746        public static Type asmTypeByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
747            return Type.getObjectType(internalNameByFqNameWithoutInnerClasses(fqName));
748        }
749    
750        @NotNull
751        public static String internalNameByFqNameWithoutInnerClasses(@NotNull FqName fqName) {
752            return JvmClassName.byFqNameWithoutInnerClasses(fqName).getInternalName();
753        }
754    
755        public static void writeOuterClassAndEnclosingMethod(
756                @NotNull ClassDescriptor descriptor,
757                @NotNull DeclarationDescriptor originalDescriptor,
758                @NotNull JetTypeMapper typeMapper,
759                @NotNull ClassBuilder v
760        ) {
761            String outerClassName = getOuterClassName(descriptor, originalDescriptor, typeMapper);
762            FunctionDescriptor function = DescriptorUtils.getParentOfType(descriptor, FunctionDescriptor.class);
763    
764            if (function != null) {
765                Method method = typeMapper.mapSignature(function).getAsmMethod();
766                v.visitOuterClass(outerClassName, method.getName(), method.getDescriptor());
767            }
768            else {
769                v.visitOuterClass(outerClassName, null, null);
770            }
771        }
772    
773        @NotNull
774        private static String getOuterClassName(@NotNull ClassDescriptor classDescriptor, @NotNull DeclarationDescriptor originalDescriptor, @NotNull JetTypeMapper typeMapper) {
775            DeclarationDescriptor container = classDescriptor.getContainingDeclaration();
776            while (container != null) {
777                if (container instanceof ClassDescriptor) {
778                    return typeMapper.mapClass((ClassDescriptor)container).getInternalName();
779                } else if (CodegenBinding.isLocalFunOrLambda(container)) {
780                    ClassDescriptor descriptor =
781                            CodegenBinding.anonymousClassForFunction(typeMapper.getBindingContext(), (FunctionDescriptor) container);
782                    return typeMapper.mapClass(descriptor).getInternalName();
783                }
784    
785                container = container.getContainingDeclaration();
786            }
787    
788            JetFile containingFile = BindingContextUtils.getContainingFile(typeMapper.getBindingContext(), originalDescriptor);
789            assert containingFile != null : "Containing file should be present for " + classDescriptor;
790            return PackagePartClassUtils.getPackagePartInternalName(containingFile);
791        }
792    
793        public static void putJavaLangClassInstance(@NotNull InstructionAdapter v, @NotNull Type type) {
794            if (isPrimitive(type)) {
795                v.getstatic(boxType(type).getInternalName(), "TYPE", "Ljava/lang/Class;");
796            }
797            else {
798                v.aconst(type);
799            }
800        }
801    }