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