001    /*
002     * Copyright 2010-2015 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.codegen;
018    
019    import com.intellij.openapi.progress.ProcessCanceledException;
020    import com.intellij.psi.PsiElement;
021    import com.intellij.util.ArrayUtil;
022    import com.intellij.util.Function;
023    import com.intellij.util.containers.ContainerUtil;
024    import kotlin.Unit;
025    import kotlin.jvm.functions.Function1;
026    import org.jetbrains.annotations.NotNull;
027    import org.jetbrains.annotations.Nullable;
028    import org.jetbrains.kotlin.backend.common.bridges.Bridge;
029    import org.jetbrains.kotlin.backend.common.bridges.ImplKt;
030    import org.jetbrains.kotlin.codegen.annotation.AnnotatedWithOnlyTargetedAnnotations;
031    import org.jetbrains.kotlin.codegen.context.*;
032    import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics;
033    import org.jetbrains.kotlin.codegen.optimization.OptimizationMethodVisitor;
034    import org.jetbrains.kotlin.codegen.state.GenerationState;
035    import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
036    import org.jetbrains.kotlin.descriptors.*;
037    import org.jetbrains.kotlin.descriptors.annotations.Annotated;
038    import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
039    import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget;
040    import org.jetbrains.kotlin.jvm.RuntimeAssertionInfo;
041    import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature;
042    import org.jetbrains.kotlin.load.java.JvmAbi;
043    import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
044    import org.jetbrains.kotlin.load.java.SpecialBuiltinMembers;
045    import org.jetbrains.kotlin.load.kotlin.nativeDeclarations.NativeKt;
046    import org.jetbrains.kotlin.name.FqName;
047    import org.jetbrains.kotlin.psi.KtNamedFunction;
048    import org.jetbrains.kotlin.resolve.BindingContext;
049    import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
050    import org.jetbrains.kotlin.resolve.DescriptorUtils;
051    import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt;
052    import org.jetbrains.kotlin.resolve.calls.callResolverUtil.CallResolverUtilKt;
053    import org.jetbrains.kotlin.resolve.constants.ArrayValue;
054    import org.jetbrains.kotlin.resolve.constants.ConstantValue;
055    import org.jetbrains.kotlin.resolve.constants.KClassValue;
056    import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
057    import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
058    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
059    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
060    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
061    import org.jetbrains.kotlin.types.KotlinType;
062    import org.jetbrains.kotlin.types.TypeUtils;
063    import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
064    import org.jetbrains.org.objectweb.asm.Label;
065    import org.jetbrains.org.objectweb.asm.MethodVisitor;
066    import org.jetbrains.org.objectweb.asm.Type;
067    import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
068    import org.jetbrains.org.objectweb.asm.commons.Method;
069    import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
070    
071    import java.io.PrintWriter;
072    import java.io.StringWriter;
073    import java.util.Collection;
074    import java.util.Iterator;
075    import java.util.List;
076    import java.util.Set;
077    
078    import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isNullableAny;
079    import static org.jetbrains.kotlin.codegen.AsmUtil.*;
080    import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.*;
081    import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION;
082    import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*;
083    import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.getSourceFromDescriptor;
084    import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
085    import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE;
086    import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.*;
087    import static org.jetbrains.org.objectweb.asm.Opcodes.*;
088    
089    public class FunctionCodegen {
090        public final GenerationState state;
091        private final JetTypeMapper typeMapper;
092        private final BindingContext bindingContext;
093        private final CodegenContext owner;
094        private final ClassBuilder v;
095        private final MemberCodegen<?> memberCodegen;
096    
097        public FunctionCodegen(
098                @NotNull CodegenContext owner,
099                @NotNull ClassBuilder v,
100                @NotNull GenerationState state,
101                @NotNull MemberCodegen<?> memberCodegen
102        ) {
103            this.owner = owner;
104            this.v = v;
105            this.state = state;
106            this.typeMapper = state.getTypeMapper();
107            this.bindingContext = state.getBindingContext();
108            this.memberCodegen = memberCodegen;
109        }
110    
111        public void gen(@NotNull KtNamedFunction function) {
112            SimpleFunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, function);
113            assert functionDescriptor != null : "No descriptor for function " + function.getText() + "\n" +
114                                                "in " + function.getContainingFile().getVirtualFile();
115    
116            if (owner.getContextKind() != OwnerKind.DEFAULT_IMPLS || function.hasBody()) {
117                generateMethod(JvmDeclarationOriginKt.OtherOrigin(function, functionDescriptor), functionDescriptor,
118                               new FunctionGenerationStrategy.FunctionDefault(state, functionDescriptor, function));
119            }
120    
121            generateDefaultIfNeeded(owner.intoFunction(functionDescriptor), functionDescriptor, owner.getContextKind(),
122                                    DefaultParameterValueLoader.DEFAULT, function);
123    
124            generateOverloadsWithDefaultValues(function, functionDescriptor, functionDescriptor);
125        }
126    
127        public void generateOverloadsWithDefaultValues(
128                @Nullable KtNamedFunction function,
129                @NotNull FunctionDescriptor functionDescriptor,
130                @NotNull FunctionDescriptor delegateFunctionDescriptor
131        ) {
132            new DefaultParameterValueSubstitutor(state).generateOverloadsIfNeeded(
133                    function, functionDescriptor, delegateFunctionDescriptor, owner.getContextKind(), v
134            );
135        }
136    
137        public void generateMethod(
138                @NotNull JvmDeclarationOrigin origin,
139                @NotNull FunctionDescriptor descriptor,
140                @NotNull FunctionGenerationStrategy strategy
141        ) {
142            generateMethod(origin, descriptor, owner.intoFunction(descriptor), strategy);
143        }
144    
145        public void generateMethod(
146                @NotNull JvmDeclarationOrigin origin,
147                @NotNull FunctionDescriptor functionDescriptor,
148                @NotNull MethodContext methodContext,
149                @NotNull FunctionGenerationStrategy strategy
150        ) {
151            OwnerKind contextKind = methodContext.getContextKind();
152            if (isInterface(functionDescriptor.getContainingDeclaration()) &&
153                functionDescriptor.getVisibility() == Visibilities.PRIVATE &&
154                contextKind != OwnerKind.DEFAULT_IMPLS) {
155                return;
156            }
157    
158            JvmMethodSignature jvmSignature = typeMapper.mapSignature(functionDescriptor, contextKind);
159            Method asmMethod = jvmSignature.getAsmMethod();
160    
161            int flags = getMethodAsmFlags(functionDescriptor, contextKind);
162            boolean isNative = NativeKt.hasNativeAnnotation(functionDescriptor);
163    
164            if (isNative && owner instanceof DelegatingFacadeContext) {
165                // Native methods are only defined in facades and do not need package part implementations
166                return;
167            }
168            MethodVisitor mv = v.newMethod(origin,
169                                           flags,
170                                           asmMethod.getName(),
171                                           asmMethod.getDescriptor(),
172                                           jvmSignature.getGenericsSignature(),
173                                           getThrownExceptions(functionDescriptor, typeMapper));
174    
175            String implClassName = CodegenContextUtil.getImplementationClassShortName(owner);
176            if (implClassName != null) {
177                v.getSerializationBindings().put(IMPL_CLASS_NAME_FOR_CALLABLE, functionDescriptor, implClassName);
178            }
179            if (CodegenContextUtil.isImplClassOwner(owner)) {
180                v.getSerializationBindings().put(METHOD_FOR_FUNCTION, functionDescriptor, asmMethod);
181            }
182    
183            generateMethodAnnotations(functionDescriptor, asmMethod, mv);
184    
185            generateParameterAnnotations(functionDescriptor, mv, typeMapper.mapSignature(functionDescriptor));
186    
187            generateBridges(functionDescriptor);
188    
189            boolean staticInCompanionObject = AnnotationUtilKt.isPlatformStaticInCompanionObject(functionDescriptor);
190            if (staticInCompanionObject) {
191                ImplementationBodyCodegen parentBodyCodegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen();
192                parentBodyCodegen.addAdditionalTask(new JvmStaticGenerator(functionDescriptor, origin, state));
193            }
194    
195            if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES || isAbstractMethod(functionDescriptor, contextKind)) {
196                generateLocalVariableTable(
197                        mv,
198                        jvmSignature,
199                        functionDescriptor,
200                        getThisTypeForFunction(functionDescriptor, methodContext, typeMapper),
201                        new Label(),
202                        new Label(),
203                        contextKind
204                );
205    
206                mv.visitEnd();
207                return;
208            }
209    
210            if (!isNative) {
211                generateMethodBody(mv, functionDescriptor, methodContext, jvmSignature, strategy, memberCodegen);
212            }
213            else if (staticInCompanionObject) {
214                // native @JvmStatic foo() in companion object should delegate to the static native function moved to the outer class
215                mv.visitCode();
216                FunctionDescriptor staticFunctionDescriptor = JvmStaticGenerator.createStaticFunctionDescriptor(functionDescriptor);
217                JvmMethodSignature jvmMethodSignature =
218                        typeMapper.mapSignature(memberCodegen.getContext().accessibleDescriptor(staticFunctionDescriptor, null));
219                Type owningType = typeMapper.mapClass((ClassifierDescriptor) staticFunctionDescriptor.getContainingDeclaration());
220                generateDelegateToMethodBody(false, mv, jvmMethodSignature.getAsmMethod(), owningType.getInternalName());
221            }
222    
223            endVisit(mv, null, origin.getElement());
224    
225            methodContext.recordSyntheticAccessorIfNeeded(functionDescriptor, bindingContext);
226        }
227    
228        private void generateMethodAnnotations(
229                @NotNull FunctionDescriptor functionDescriptor,
230                Method asmMethod,
231                MethodVisitor mv
232        ) {
233            AnnotationCodegen annotationCodegen = AnnotationCodegen.forMethod(mv, typeMapper);
234    
235            if (functionDescriptor instanceof PropertyAccessorDescriptor) {
236                AnnotationUseSiteTarget target = functionDescriptor instanceof PropertySetterDescriptor ? PROPERTY_SETTER : PROPERTY_GETTER;
237                annotationCodegen.genAnnotations(functionDescriptor, asmMethod.getReturnType(), target);
238            }
239            else {
240                annotationCodegen.genAnnotations(functionDescriptor, asmMethod.getReturnType());
241            }
242    
243            writePackageFacadeMethodAnnotationsIfNeeded(mv);
244        }
245    
246        private void writePackageFacadeMethodAnnotationsIfNeeded(MethodVisitor mv) {
247            if (owner instanceof PackageFacadeContext) {
248                PackageFacadeContext packageFacadeContext = (PackageFacadeContext) owner;
249                Type delegateToClassType = packageFacadeContext.getPublicFacadeType();
250                if (delegateToClassType != null) {
251                    String className = delegateToClassType.getClassName();
252                    AnnotationVisitor
253                            av = mv.visitAnnotation(AsmUtil.asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_DELEGATED_METHOD), true);
254                    av.visit(JvmAnnotationNames.IMPLEMENTATION_CLASS_NAME_FIELD_NAME, className);
255                    av.visitEnd();
256                }
257            }
258        }
259    
260        private void generateParameterAnnotations(
261                @NotNull FunctionDescriptor functionDescriptor,
262                @NotNull MethodVisitor mv,
263                @NotNull JvmMethodSignature jvmSignature
264        ) {
265            Iterator<ValueParameterDescriptor> iterator = functionDescriptor.getValueParameters().iterator();
266            List<JvmMethodParameterSignature> kotlinParameterTypes = jvmSignature.getValueParameters();
267    
268            for (int i = 0; i < kotlinParameterTypes.size(); i++) {
269                JvmMethodParameterSignature parameterSignature = kotlinParameterTypes.get(i);
270                JvmMethodParameterKind kind = parameterSignature.getKind();
271                if (kind.isSkippedInGenericSignature()) {
272                    markEnumOrInnerConstructorParameterAsSynthetic(mv, i);
273                    continue;
274                }
275    
276                if (kind == JvmMethodParameterKind.VALUE) {
277                    ValueParameterDescriptor parameter = iterator.next();
278                    if (parameter.getIndex() != i) {
279                        v.getSerializationBindings().put(INDEX_FOR_VALUE_PARAMETER, parameter, i);
280                    }
281                    AnnotationCodegen annotationCodegen = AnnotationCodegen.forParameter(i, mv, typeMapper);
282    
283                    if (functionDescriptor instanceof PropertySetterDescriptor) {
284                        PropertyDescriptor propertyDescriptor = ((PropertySetterDescriptor) functionDescriptor).getCorrespondingProperty();
285                        Annotated targetedAnnotations = new AnnotatedWithOnlyTargetedAnnotations(propertyDescriptor);
286                        annotationCodegen.genAnnotations(targetedAnnotations, parameterSignature.getAsmType(), SETTER_PARAMETER);
287                    }
288    
289                    if (functionDescriptor instanceof ConstructorDescriptor) {
290                        annotationCodegen.genAnnotations(parameter, parameterSignature.getAsmType(), CONSTRUCTOR_PARAMETER);
291                    }
292                    else {
293                        annotationCodegen.genAnnotations(parameter, parameterSignature.getAsmType());
294                    }
295                }
296                else if (kind == JvmMethodParameterKind.RECEIVER) {
297                    ReceiverParameterDescriptor receiver = ((functionDescriptor instanceof PropertyAccessorDescriptor)
298                                                 ? ((PropertyAccessorDescriptor) functionDescriptor).getCorrespondingProperty()
299                                                 : functionDescriptor).getExtensionReceiverParameter();
300                    if (receiver != null) {
301                        AnnotationCodegen annotationCodegen = AnnotationCodegen.forParameter(i, mv, typeMapper);
302                        Annotated targetedAnnotations = new AnnotatedWithOnlyTargetedAnnotations(receiver.getType());
303                        annotationCodegen.genAnnotations(targetedAnnotations, parameterSignature.getAsmType(), RECEIVER);
304                    }
305                }
306            }
307        }
308    
309        private void markEnumOrInnerConstructorParameterAsSynthetic(MethodVisitor mv, int i) {
310            // IDEA's ClsPsi builder fails to annotate synthetic parameters
311            if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return;
312    
313            // This is needed to avoid RuntimeInvisibleParameterAnnotations error in javac:
314            // see MethodWriter.visitParameterAnnotation()
315    
316            AnnotationVisitor av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", true);
317            if (av != null) {
318                av.visitEnd();
319            }
320        }
321    
322        @Nullable
323        private static Type getThisTypeForFunction(
324                @NotNull FunctionDescriptor functionDescriptor,
325                @NotNull MethodContext context,
326                @NotNull JetTypeMapper typeMapper
327        ) {
328            ReceiverParameterDescriptor dispatchReceiver = functionDescriptor.getDispatchReceiverParameter();
329            if (functionDescriptor instanceof ConstructorDescriptor) {
330                return typeMapper.mapType(functionDescriptor);
331            }
332            else if (dispatchReceiver != null) {
333                return typeMapper.mapType(dispatchReceiver.getType());
334            }
335            else if (isFunctionLiteral(functionDescriptor) ||
336                     isLocalFunction(functionDescriptor) ||
337                     isFunctionExpression(functionDescriptor)) {
338                return typeMapper.mapType(context.getThisDescriptor());
339            }
340            else {
341                return null;
342            }
343        }
344    
345        public static void generateMethodBody(
346                @NotNull MethodVisitor mv,
347                @NotNull FunctionDescriptor functionDescriptor,
348                @NotNull MethodContext context,
349                @NotNull JvmMethodSignature signature,
350                @NotNull FunctionGenerationStrategy strategy,
351                @NotNull MemberCodegen<?> parentCodegen
352        ) {
353            mv.visitCode();
354    
355            Label methodBegin = new Label();
356            mv.visitLabel(methodBegin);
357    
358            JetTypeMapper typeMapper = parentCodegen.typeMapper;
359            if (BuiltinSpecialBridgesUtil.shouldHaveTypeSafeBarrier(functionDescriptor, getSignatureMapper(typeMapper))) {
360                generateTypeCheckBarrierIfNeeded(
361                        new InstructionAdapter(mv), functionDescriptor, signature.getReturnType(), /* delegateParameterType = */null);
362            }
363    
364            Label methodEnd;
365    
366            int functionFakeIndex = -1;
367            int lambdaFakeIndex = -1;
368    
369            if (context.getParentContext() instanceof DelegatingFacadeContext) {
370                generateFacadeDelegateMethodBody(mv, signature.getAsmMethod(), (DelegatingFacadeContext) context.getParentContext());
371                methodEnd = new Label();
372            }
373            else {
374                FrameMap frameMap = createFrameMap(parentCodegen.state, functionDescriptor, signature, isStaticMethod(context.getContextKind(),
375                                                                                                                      functionDescriptor));
376                if (context.isInlineFunction()) {
377                    functionFakeIndex = frameMap.enterTemp(Type.INT_TYPE);
378                }
379    
380                if (context.isInliningLambda()) {
381                    lambdaFakeIndex = frameMap.enterTemp(Type.INT_TYPE);
382                }
383    
384                Label methodEntry = new Label();
385                mv.visitLabel(methodEntry);
386                context.setMethodStartLabel(methodEntry);
387    
388                if (!JetTypeMapper.isAccessor(functionDescriptor)) {
389                    genNotNullAssertionsForParameters(new InstructionAdapter(mv), parentCodegen.state, functionDescriptor, frameMap);
390                }
391                methodEnd = new Label();
392                context.setMethodEndLabel(methodEnd);
393                strategy.generateBody(mv, frameMap, signature, context, parentCodegen);
394            }
395    
396            mv.visitLabel(methodEnd);
397    
398            Type thisType = getThisTypeForFunction(functionDescriptor, context, typeMapper);
399            generateLocalVariableTable(mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind());
400    
401            if (context.isInlineFunction() && functionFakeIndex != -1) {
402                mv.visitLocalVariable(
403                        JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION + functionDescriptor.getName().asString(),
404                        Type.INT_TYPE.getDescriptor(), null,
405                        methodBegin, methodEnd,
406                        functionFakeIndex);
407            }
408    
409            if (context.isInliningLambda() && thisType != null && lambdaFakeIndex != -1) {
410                String name = thisType.getClassName();
411                int indexOfLambdaOrdinal = name.lastIndexOf("$");
412                if (indexOfLambdaOrdinal > 0) {
413                    int lambdaOrdinal = Integer.parseInt(name.substring(indexOfLambdaOrdinal + 1));
414                    mv.visitLocalVariable(
415                            JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT + lambdaOrdinal,
416                            Type.INT_TYPE.getDescriptor(), null,
417                            methodBegin, methodEnd,
418                            lambdaFakeIndex);
419                }
420            }
421        }
422    
423        private static void generateLocalVariableTable(
424                @NotNull MethodVisitor mv,
425                @NotNull JvmMethodSignature jvmMethodSignature,
426                @NotNull FunctionDescriptor functionDescriptor,
427                @Nullable Type thisType,
428                @NotNull Label methodBegin,
429                @NotNull Label methodEnd,
430                @NotNull OwnerKind ownerKind
431        ) {
432            Iterator<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters().iterator();
433            List<JvmMethodParameterSignature> params = jvmMethodSignature.getValueParameters();
434            int shift = 0;
435    
436            boolean isStatic = AsmUtil.isStaticMethod(ownerKind, functionDescriptor);
437            if (!isStatic) {
438                //add this
439                if (thisType != null) {
440                    mv.visitLocalVariable("this", thisType.getDescriptor(), null, methodBegin, methodEnd, shift);
441                }
442                else {
443                    //TODO: provide thisType for callable reference
444                }
445                shift++;
446            }
447    
448            for (int i = 0; i < params.size(); i++) {
449                JvmMethodParameterSignature param = params.get(i);
450                JvmMethodParameterKind kind = param.getKind();
451                String parameterName;
452    
453                if (kind == JvmMethodParameterKind.VALUE) {
454                    ValueParameterDescriptor parameter = valueParameters.next();
455                    parameterName = parameter.getName().asString();
456                }
457                else {
458                    String lowercaseKind = kind.name().toLowerCase();
459                    parameterName = needIndexForVar(kind)
460                                    ? "$" + lowercaseKind + "$" + i
461                                    : "$" + lowercaseKind;
462                }
463    
464                Type type = param.getAsmType();
465                mv.visitLocalVariable(parameterName, type.getDescriptor(), null, methodBegin, methodEnd, shift);
466                shift += type.getSize();
467            }
468        }
469    
470        private static void generateFacadeDelegateMethodBody(
471                @NotNull MethodVisitor mv,
472                @NotNull Method asmMethod,
473                @NotNull DelegatingFacadeContext context
474        ) {
475            generateDelegateToMethodBody(true, mv, asmMethod, context.getDelegateToClassType().getInternalName());
476        }
477    
478        private static void generateDelegateToMethodBody(
479                boolean isStatic,
480                @NotNull MethodVisitor mv,
481                @NotNull Method asmMethod,
482                @NotNull String classToDelegateTo
483        ) {
484            InstructionAdapter iv = new InstructionAdapter(mv);
485            Type[] argTypes = asmMethod.getArgumentTypes();
486    
487            // The first line of some package file is written to the line number attribute of a static delegate to allow to 'step into' it
488            // This is similar to what javac does with bridge methods
489            Label label = new Label();
490            iv.visitLabel(label);
491            iv.visitLineNumber(1, label);
492    
493            int k = isStatic ? 0 : 1;
494            for (Type argType : argTypes) {
495                iv.load(k, argType);
496                k += argType.getSize();
497            }
498            iv.invokestatic(classToDelegateTo, asmMethod.getName(), asmMethod.getDescriptor(), false);
499            iv.areturn(asmMethod.getReturnType());
500        }
501    
502        private static boolean needIndexForVar(JvmMethodParameterKind kind) {
503            return kind == JvmMethodParameterKind.CAPTURED_LOCAL_VARIABLE ||
504                   kind == JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL ||
505                   kind == JvmMethodParameterKind.SUPER_CALL_PARAM;
506        }
507    
508        public static void endVisit(MethodVisitor mv, @Nullable String description, @Nullable PsiElement method) {
509            try {
510                mv.visitMaxs(-1, -1);
511                mv.visitEnd();
512            }
513            catch (ProcessCanceledException e) {
514                throw e;
515            }
516            catch (Throwable t) {
517                String bytecode = renderByteCodeIfAvailable(mv);
518                throw new CompilationException(
519                        "wrong code generated" +
520                        (description != null ? " for " + description : "") +
521                        t.getClass().getName() +
522                        " " +
523                        t.getMessage() +
524                        (bytecode != null ? "\nbytecode:\n" + bytecode : ""),
525                        t, method);
526            }
527        }
528    
529        private static String renderByteCodeIfAvailable(MethodVisitor mv) {
530            String bytecode = null;
531    
532            if (mv instanceof OptimizationMethodVisitor) {
533                mv = ((OptimizationMethodVisitor) mv).getTraceMethodVisitorIfPossible();
534            }
535    
536            if (mv instanceof TraceMethodVisitor) {
537                TraceMethodVisitor traceMethodVisitor = (TraceMethodVisitor) mv;
538                StringWriter sw = new StringWriter();
539                PrintWriter pw = new PrintWriter(sw);
540                traceMethodVisitor.p.print(pw);
541                pw.close();
542                bytecode = sw.toString();
543            }
544            return bytecode;
545        }
546    
547        public void generateBridges(@NotNull FunctionDescriptor descriptor) {
548            if (descriptor instanceof ConstructorDescriptor) return;
549            if (owner.getContextKind() == OwnerKind.DEFAULT_IMPLS) return;
550            if (isInterface(descriptor.getContainingDeclaration())) return;
551    
552            // equals(Any?), hashCode(), toString() never need bridges
553            if (isMethodOfAny(descriptor)) return;
554    
555            // If the function doesn't have a physical declaration among super-functions, it's a SAM adapter or alike and doesn't need bridges
556            if (CallResolverUtilKt.isOrOverridesSynthesized(descriptor)) return;
557    
558            boolean isSpecial = SpecialBuiltinMembers.getOverriddenBuiltinWithDifferentJvmDescriptor(descriptor) != null;
559    
560            Set<Bridge<Method>> bridgesToGenerate;
561            if (!isSpecial) {
562                bridgesToGenerate = ImplKt.generateBridgesForFunctionDescriptor(
563                        descriptor,
564                        getSignatureMapper(typeMapper)
565                );
566                if (!bridgesToGenerate.isEmpty()) {
567                    PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null;
568                    boolean isSpecialBridge =
569                            BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(descriptor) != null;
570    
571                    for (Bridge<Method> bridge : bridgesToGenerate) {
572                        generateBridge(origin, descriptor, bridge.getFrom(), bridge.getTo(), isSpecialBridge, false);
573                    }
574                }
575            }
576            else {
577                Set<BridgeForBuiltinSpecial<Method>> specials = BuiltinSpecialBridgesUtil.generateBridgesForBuiltinSpecial(
578                        descriptor,
579                        getSignatureMapper(typeMapper)
580                );
581    
582                if (!specials.isEmpty()) {
583                    PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null;
584                    for (BridgeForBuiltinSpecial<Method> bridge : specials) {
585                        generateBridge(
586                                origin, descriptor, bridge.getFrom(), bridge.getTo(),
587                                bridge.isSpecial(), bridge.isDelegateToSuper());
588                    }
589                }
590    
591                if (!descriptor.getKind().isReal() && isAbstractMethod(descriptor, OwnerKind.IMPLEMENTATION)) {
592                    CallableDescriptor overridden = SpecialBuiltinMembers.getOverriddenBuiltinWithDifferentJvmDescriptor(descriptor);
593                    assert overridden != null;
594    
595                    Method method = typeMapper.mapSignature(descriptor).getAsmMethod();
596                    int flags = ACC_ABSTRACT | getVisibilityAccessFlag(descriptor);
597                    v.newMethod(JvmDeclarationOriginKt.OtherOrigin(overridden), flags, method.getName(), method.getDescriptor(), null, null);
598                }
599            }
600        }
601    
602        @NotNull
603        private static Function1<FunctionDescriptor, Method> getSignatureMapper(final @NotNull  JetTypeMapper typeMapper) {
604            return new Function1<FunctionDescriptor, Method>() {
605                @Override
606                public Method invoke(FunctionDescriptor descriptor) {
607                    return typeMapper.mapSignature(descriptor).getAsmMethod();
608                }
609            };
610        }
611    
612        private static boolean isMethodOfAny(@NotNull FunctionDescriptor descriptor) {
613            String name = descriptor.getName().asString();
614            List<ValueParameterDescriptor> parameters = descriptor.getValueParameters();
615            if (parameters.isEmpty()) {
616                return name.equals("hashCode") || name.equals("toString");
617            }
618            else if (parameters.size() == 1 && name.equals("equals")) {
619                return isNullableAny(parameters.get(0).getType());
620            }
621            return false;
622        }
623    
624        @NotNull
625        public static String[] getThrownExceptions(@NotNull FunctionDescriptor function, @NotNull final JetTypeMapper mapper) {
626            AnnotationDescriptor annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.throws"));
627            if (annotation == null) {
628                annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.jvm.Throws"));
629            }
630    
631            if (annotation == null) return ArrayUtil.EMPTY_STRING_ARRAY;
632    
633            Collection<ConstantValue<?>> values = annotation.getAllValueArguments().values();
634            if (values.isEmpty()) return ArrayUtil.EMPTY_STRING_ARRAY;
635    
636            Object value = values.iterator().next();
637            if (!(value instanceof ArrayValue)) return ArrayUtil.EMPTY_STRING_ARRAY;
638            ArrayValue arrayValue = (ArrayValue) value;
639    
640            List<String> strings = ContainerUtil.mapNotNull(
641                    arrayValue.getValue(),
642                    new Function<ConstantValue<?>, String>() {
643                        @Override
644                        public String fun(ConstantValue<?> constant) {
645                            if (constant instanceof KClassValue) {
646                                KClassValue classValue = (KClassValue) constant;
647                                ClassDescriptor classDescriptor = DescriptorUtils.getClassDescriptorForType(classValue.getValue());
648                                return mapper.mapClass(classDescriptor).getInternalName();
649                            }
650                            return null;
651                        }
652                    }
653            );
654            return ArrayUtil.toStringArray(strings);
655        }
656    
657        void generateDefaultIfNeeded(
658                @NotNull MethodContext owner,
659                @NotNull FunctionDescriptor functionDescriptor,
660                @NotNull OwnerKind kind,
661                @NotNull DefaultParameterValueLoader loadStrategy,
662                @Nullable KtNamedFunction function
663        ) {
664            DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration();
665    
666            if (kind != OwnerKind.DEFAULT_IMPLS && isInterface(contextClass)) {
667                return;
668            }
669    
670            if (!isDefaultNeeded(functionDescriptor)) {
671                return;
672            }
673    
674            int flags = getVisibilityAccessFlag(functionDescriptor) |
675                        getDeprecatedAccessFlag(functionDescriptor) |
676                        ACC_SYNTHETIC;
677            if (!(functionDescriptor instanceof ConstructorDescriptor)) {
678                flags |= ACC_STATIC | ACC_BRIDGE;
679            }
680            // $default methods are never private to be accessible from other class files (e.g. inner) without the need of synthetic accessors
681            flags &= ~ACC_PRIVATE;
682    
683            Method defaultMethod = typeMapper.mapDefaultMethod(functionDescriptor, kind);
684    
685            MethodVisitor mv = v.newMethod(
686                    JvmDeclarationOriginKt.Synthetic(function, functionDescriptor),
687                    flags,
688                    defaultMethod.getName(),
689                    defaultMethod.getDescriptor(), null,
690                    getThrownExceptions(functionDescriptor, typeMapper)
691            );
692    
693            // Only method annotations are copied to the $default method. Parameter annotations are not copied until there are valid use cases;
694            // enum constructors have two additional synthetic parameters which somewhat complicate this task
695            AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(functionDescriptor, defaultMethod.getReturnType());
696    
697            if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
698                if (this.owner instanceof DelegatingFacadeContext) {
699                    mv.visitCode();
700                    generateFacadeDelegateMethodBody(mv, defaultMethod, (DelegatingFacadeContext) this.owner);
701                    endVisit(mv, "default method delegation", getSourceFromDescriptor(functionDescriptor));
702                }
703                else {
704                    mv.visitCode();
705                    generateDefaultImplBody(owner, functionDescriptor, mv, loadStrategy, function, memberCodegen);
706                    endVisit(mv, "default method", getSourceFromDescriptor(functionDescriptor));
707                }
708            }
709        }
710    
711        public static void generateDefaultImplBody(
712                @NotNull MethodContext methodContext,
713                @NotNull FunctionDescriptor functionDescriptor,
714                @NotNull MethodVisitor mv,
715                @NotNull DefaultParameterValueLoader loadStrategy,
716                @Nullable KtNamedFunction function,
717                @NotNull MemberCodegen<?> parentCodegen
718        ) {
719            GenerationState state = parentCodegen.state;
720            JvmMethodSignature signature = state.getTypeMapper().mapSignature(functionDescriptor, methodContext.getContextKind());
721    
722            boolean isStatic = isStaticMethod(methodContext.getContextKind(), functionDescriptor);
723            FrameMap frameMap = createFrameMap(state, functionDescriptor, signature, isStatic);
724    
725            ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, signature.getReturnType(), methodContext, state, parentCodegen);
726    
727            CallGenerator generator = codegen.getOrCreateCallGenerator(functionDescriptor, function);
728    
729            loadExplicitArgumentsOnStack(OBJECT_TYPE, isStatic, signature, generator);
730    
731            List<JvmMethodParameterSignature> mappedParameters = signature.getValueParameters();
732            int capturedArgumentsCount = 0;
733            while (capturedArgumentsCount < mappedParameters.size() &&
734                   mappedParameters.get(capturedArgumentsCount).getKind() != JvmMethodParameterKind.VALUE) {
735                capturedArgumentsCount++;
736            }
737    
738            InstructionAdapter iv = new InstructionAdapter(mv);
739    
740            int maskIndex = 0;
741            List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters();
742            for (int index = 0; index < valueParameters.size(); index++) {
743                if (index % Integer.SIZE == 0) {
744                    maskIndex = frameMap.enterTemp(Type.INT_TYPE);
745                }
746                ValueParameterDescriptor parameterDescriptor = valueParameters.get(index);
747                Type type = mappedParameters.get(capturedArgumentsCount + index).getAsmType();
748    
749                int parameterIndex = frameMap.getIndex(parameterDescriptor);
750                if (parameterDescriptor.declaresDefaultValue()) {
751                    iv.load(maskIndex, Type.INT_TYPE);
752                    iv.iconst(1 << (index % Integer.SIZE));
753                    iv.and(Type.INT_TYPE);
754                    Label loadArg = new Label();
755                    iv.ifeq(loadArg);
756    
757                    StackValue.local(parameterIndex, type).store(loadStrategy.genValue(parameterDescriptor, codegen), iv);
758    
759                    iv.mark(loadArg);
760                }
761    
762                generator.putValueIfNeeded(parameterDescriptor, type, StackValue.local(parameterIndex, type));
763            }
764    
765            CallableMethod method = state.getTypeMapper().mapToCallableMethod(functionDescriptor, false);
766    
767            generator.genCallWithoutAssertions(method, codegen);
768    
769            iv.areturn(signature.getReturnType());
770        }
771    
772        @NotNull
773        private static FrameMap createFrameMap(
774                @NotNull GenerationState state,
775                @NotNull FunctionDescriptor function,
776                @NotNull JvmMethodSignature signature,
777                boolean isStatic
778        ) {
779            FrameMap frameMap = new FrameMap();
780            if (!isStatic) {
781                frameMap.enterTemp(OBJECT_TYPE);
782            }
783    
784            for (JvmMethodParameterSignature parameter : signature.getValueParameters()) {
785                if (parameter.getKind() == JvmMethodParameterKind.RECEIVER) {
786                    ReceiverParameterDescriptor receiverParameter = function.getExtensionReceiverParameter();
787                    if (receiverParameter != null) {
788                        frameMap.enter(receiverParameter, state.getTypeMapper().mapType(receiverParameter));
789                    }
790                }
791                else if (parameter.getKind() != JvmMethodParameterKind.VALUE) {
792                    frameMap.enterTemp(parameter.getAsmType());
793                }
794            }
795    
796            for (ValueParameterDescriptor parameter : function.getValueParameters()) {
797                frameMap.enter(parameter, state.getTypeMapper().mapType(parameter));
798            }
799    
800            return frameMap;
801        }
802    
803        private static void loadExplicitArgumentsOnStack(
804                @NotNull Type ownerType,
805                boolean isStatic,
806                @NotNull JvmMethodSignature signature,
807                @NotNull CallGenerator callGenerator
808        ) {
809            int var = 0;
810            if (!isStatic) {
811                callGenerator.putValueIfNeeded(null, ownerType, StackValue.local(var, ownerType));
812                var += ownerType.getSize();
813            }
814    
815            for (JvmMethodParameterSignature parameterSignature : signature.getValueParameters()) {
816                if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) {
817                    Type type = parameterSignature.getAsmType();
818                    callGenerator.putValueIfNeeded(null, type, StackValue.local(var, type));
819                    var += type.getSize();
820                }
821            }
822        }
823    
824        private static boolean isDefaultNeeded(FunctionDescriptor functionDescriptor) {
825            boolean needed = false;
826            if (functionDescriptor != null) {
827                for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) {
828                    if (parameterDescriptor.declaresDefaultValue()) {
829                        needed = true;
830                        break;
831                    }
832                }
833            }
834            return needed;
835        }
836    
837        private void generateBridge(
838                @Nullable PsiElement origin,
839                @NotNull FunctionDescriptor descriptor,
840                @NotNull Method bridge,
841                @NotNull Method delegateTo,
842                boolean isSpecialBridge,
843                boolean isStubDeclarationWithDelegationToSuper
844        ) {
845            boolean isSpecialOrDelegationToSuper = isSpecialBridge || isStubDeclarationWithDelegationToSuper;
846            int flags = ACC_PUBLIC | ACC_BRIDGE | (!isSpecialOrDelegationToSuper ? ACC_SYNTHETIC : 0) | (isSpecialBridge ? ACC_FINAL : 0); // TODO.
847    
848            MethodVisitor mv =
849                    v.newMethod(JvmDeclarationOriginKt.Bridge(descriptor, origin), flags, bridge.getName(), bridge.getDescriptor(), null, null);
850            if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
851    
852            mv.visitCode();
853    
854            Type[] argTypes = bridge.getArgumentTypes();
855            Type[] originalArgTypes = delegateTo.getArgumentTypes();
856    
857            InstructionAdapter iv = new InstructionAdapter(mv);
858            MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv);
859    
860            if (delegateTo.getArgumentTypes().length == 1 && isSpecialBridge) {
861                generateTypeCheckBarrierIfNeeded(iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes()[0]);
862            }
863    
864            iv.load(0, OBJECT_TYPE);
865            for (int i = 0, reg = 1; i < argTypes.length; i++) {
866                StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
867                //noinspection AssignmentToForLoopParameter
868                reg += argTypes[i].getSize();
869            }
870    
871            if (isStubDeclarationWithDelegationToSuper) {
872                ClassDescriptor parentClass = getSuperClassDescriptor((ClassDescriptor) descriptor.getContainingDeclaration());
873                assert parentClass != null;
874                String parentInternalName = typeMapper.mapClass(parentClass).getInternalName();
875                iv.invokespecial(parentInternalName, delegateTo.getName(), delegateTo.getDescriptor());
876            }
877            else {
878                iv.invokevirtual(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor());
879            }
880    
881            StackValue.coerce(delegateTo.getReturnType(), bridge.getReturnType(), iv);
882            iv.areturn(bridge.getReturnType());
883    
884            endVisit(mv, "bridge method", origin);
885        }
886    
887        private static void generateTypeCheckBarrierIfNeeded(
888                @NotNull InstructionAdapter iv,
889                @NotNull FunctionDescriptor descriptor,
890                @NotNull Type returnType,
891                @Nullable final Type delegateParameterType
892        ) {
893            BuiltinMethodsWithSpecialGenericSignature.DefaultValue defaultValue =
894                    BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor);
895            if (defaultValue == null) return;
896    
897            assert descriptor.getValueParameters().size() == 1 : "Should be descriptor with one value parameter, but found: " + descriptor;
898    
899            boolean isCheckForAny = delegateParameterType == null || OBJECT_TYPE.equals(delegateParameterType);
900    
901            final KotlinType kotlinType = descriptor.getValueParameters().get(0).getType();
902    
903            if (isCheckForAny && TypeUtils.isNullableType(kotlinType)) return;
904    
905            iv.load(1, OBJECT_TYPE);
906    
907            Label afterBarrier = new Label();
908    
909            if (isCheckForAny) {
910                assert !TypeUtils.isNullableType(kotlinType) : "Only bridges for not-nullable types are necessary";
911                iv.ifnonnull(afterBarrier);
912            }
913            else {
914                CodegenUtilKt.generateIsCheck(iv, kotlinType, new Function1<InstructionAdapter, Unit>() {
915                    @Override
916                    public Unit invoke(InstructionAdapter adapter) {
917                        TypeIntrinsics.instanceOf(adapter, kotlinType, boxType(delegateParameterType));
918                        return Unit.INSTANCE;
919                    }
920                });
921                iv.ifne(afterBarrier);
922            }
923    
924            StackValue.constant(defaultValue.getValue(), returnType).put(returnType, iv);
925            iv.areturn(returnType);
926    
927            iv.visitLabel(afterBarrier);
928        }
929    
930        public void genDelegate(@NotNull FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) {
931            genDelegate(functionDescriptor, overriddenDescriptor.getOriginal(),
932                        (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(), field);
933        }
934    
935        public void genDelegate(
936                @NotNull final FunctionDescriptor delegateFunction,
937                final FunctionDescriptor delegatedTo,
938                final ClassDescriptor toClass,
939                final StackValue field
940        ) {
941            generateMethod(
942                    JvmDeclarationOriginKt.Delegation(DescriptorToSourceUtils.descriptorToDeclaration(delegatedTo), delegateFunction), delegateFunction,
943                    new FunctionGenerationStrategy() {
944                        @Override
945                        public void generateBody(
946                                @NotNull MethodVisitor mv,
947                                @NotNull FrameMap frameMap,
948                                @NotNull JvmMethodSignature signature,
949                                @NotNull MethodContext context,
950                                @NotNull MemberCodegen<?> parentCodegen
951                        ) {
952                            Method delegateToMethod = typeMapper.mapSignature(delegatedTo).getAsmMethod();
953                            Method delegateMethod = typeMapper.mapSignature(delegateFunction).getAsmMethod();
954    
955                            Type[] argTypes = delegateMethod.getArgumentTypes();
956                            Type[] originalArgTypes = delegateToMethod.getArgumentTypes();
957    
958                            InstructionAdapter iv = new InstructionAdapter(mv);
959                            iv.load(0, OBJECT_TYPE);
960                            field.put(field.type, iv);
961                            for (int i = 0, reg = 1; i < argTypes.length; i++) {
962                                StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
963                                //noinspection AssignmentToForLoopParameter
964                                reg += argTypes[i].getSize();
965                            }
966    
967                            String internalName = typeMapper.mapType(toClass).getInternalName();
968                            if (toClass.getKind() == ClassKind.INTERFACE) {
969                                iv.invokeinterface(internalName, delegateToMethod.getName(), delegateToMethod.getDescriptor());
970                            }
971                            else {
972                                iv.invokevirtual(internalName, delegateToMethod.getName(), delegateToMethod.getDescriptor());
973                            }
974    
975                            StackValue stackValue = AsmUtil.genNotNullAssertions(
976                                    state,
977                                    StackValue.onStack(delegateToMethod.getReturnType()),
978                                    RuntimeAssertionInfo.create(
979                                            delegateFunction.getReturnType(),
980                                            delegatedTo.getReturnType(),
981                                            new RuntimeAssertionInfo.DataFlowExtras.OnlyMessage(delegatedTo.getName() + "(...)")
982                                    )
983                            );
984    
985                            stackValue.put(delegateMethod.getReturnType(), iv);
986    
987                            iv.areturn(delegateMethod.getReturnType());
988                        }
989                    }
990            );
991        }
992    }