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    
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            if (BuiltinSpecialBridgesUtil.shouldHaveTypeSafeBarrier(functionDescriptor, getSignatureMapper(typeMapper))) {
358                generateTypeCheckBarrierIfNeeded(
359                        new InstructionAdapter(mv), functionDescriptor, signature.getReturnType(), /* delegateParameterType = */null);
360            }
361    
362            Label methodEnd;
363    
364            int functionFakeIndex = -1;
365            int lambdaFakeIndex = -1;
366    
367            if (context.getParentContext() instanceof DelegatingFacadeContext) {
368                generateFacadeDelegateMethodBody(mv, signature.getAsmMethod(), (DelegatingFacadeContext) context.getParentContext());
369                methodEnd = new Label();
370            }
371            else {
372                FrameMap frameMap = createFrameMap(parentCodegen.state, functionDescriptor, signature, isStaticMethod(context.getContextKind(),
373                                                                                                                      functionDescriptor));
374                if (context.isInlineMethodContext()) {
375                    functionFakeIndex = frameMap.enterTemp(Type.INT_TYPE);
376                }
377    
378                if (context instanceof InlineLambdaContext) {
379                    lambdaFakeIndex = frameMap.enterTemp(Type.INT_TYPE);
380                }
381    
382                Label methodEntry = new Label();
383                mv.visitLabel(methodEntry);
384                context.setMethodStartLabel(methodEntry);
385    
386                if (!JetTypeMapper.isAccessor(functionDescriptor)) {
387                    genNotNullAssertionsForParameters(new InstructionAdapter(mv), parentCodegen.state, functionDescriptor, frameMap);
388                }
389                methodEnd = new Label();
390                context.setMethodEndLabel(methodEnd);
391                strategy.generateBody(mv, frameMap, signature, context, parentCodegen);
392            }
393    
394            mv.visitLabel(methodEnd);
395    
396            Type thisType = getThisTypeForFunction(functionDescriptor, context, typeMapper);
397            generateLocalVariableTable(mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind());
398    
399            if (context.isInlineMethodContext() && functionFakeIndex != -1) {
400                mv.visitLocalVariable(
401                        JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION + functionDescriptor.getName().asString(),
402                        Type.INT_TYPE.getDescriptor(), null,
403                        methodBegin, methodEnd,
404                        functionFakeIndex);
405            }
406    
407            if (context instanceof InlineLambdaContext && thisType != null && lambdaFakeIndex != -1) {
408                String name = thisType.getClassName();
409                int indexOfLambdaOrdinal = name.lastIndexOf("$");
410                if (indexOfLambdaOrdinal > 0) {
411                    int lambdaOrdinal = Integer.parseInt(name.substring(indexOfLambdaOrdinal + 1));
412                    mv.visitLocalVariable(
413                            JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT + lambdaOrdinal,
414                            Type.INT_TYPE.getDescriptor(), null,
415                            methodBegin, methodEnd,
416                            lambdaFakeIndex);
417                }
418            }
419        }
420    
421        private static void generateLocalVariableTable(
422                @NotNull MethodVisitor mv,
423                @NotNull JvmMethodSignature jvmMethodSignature,
424                @NotNull FunctionDescriptor functionDescriptor,
425                @Nullable Type thisType,
426                @NotNull Label methodBegin,
427                @NotNull Label methodEnd,
428                @NotNull OwnerKind ownerKind
429        ) {
430            Iterator<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters().iterator();
431            List<JvmMethodParameterSignature> params = jvmMethodSignature.getValueParameters();
432            int shift = 0;
433    
434            boolean isStatic = AsmUtil.isStaticMethod(ownerKind, functionDescriptor);
435            if (!isStatic) {
436                //add this
437                if (thisType != null) {
438                    mv.visitLocalVariable("this", thisType.getDescriptor(), null, methodBegin, methodEnd, shift);
439                }
440                else {
441                    //TODO: provide thisType for callable reference
442                }
443                shift++;
444            }
445    
446            for (int i = 0; i < params.size(); i++) {
447                JvmMethodParameterSignature param = params.get(i);
448                JvmMethodParameterKind kind = param.getKind();
449                String parameterName;
450    
451                if (kind == JvmMethodParameterKind.VALUE) {
452                    ValueParameterDescriptor parameter = valueParameters.next();
453                    parameterName = parameter.getName().asString();
454                }
455                else {
456                    String lowercaseKind = kind.name().toLowerCase();
457                    parameterName = needIndexForVar(kind)
458                                    ? "$" + lowercaseKind + "$" + i
459                                    : "$" + lowercaseKind;
460                }
461    
462                Type type = param.getAsmType();
463                mv.visitLocalVariable(parameterName, type.getDescriptor(), null, methodBegin, methodEnd, shift);
464                shift += type.getSize();
465            }
466        }
467    
468        private static void generateFacadeDelegateMethodBody(
469                @NotNull MethodVisitor mv,
470                @NotNull Method asmMethod,
471                @NotNull DelegatingFacadeContext context
472        ) {
473            generateDelegateToMethodBody(true, mv, asmMethod, context.getDelegateToClassType().getInternalName());
474        }
475    
476        private static void generateDelegateToMethodBody(
477                boolean isStatic,
478                @NotNull MethodVisitor mv,
479                @NotNull Method asmMethod,
480                @NotNull String classToDelegateTo
481        ) {
482            InstructionAdapter iv = new InstructionAdapter(mv);
483            Type[] argTypes = asmMethod.getArgumentTypes();
484    
485            // The first line of some package file is written to the line number attribute of a static delegate to allow to 'step into' it
486            // This is similar to what javac does with bridge methods
487            Label label = new Label();
488            iv.visitLabel(label);
489            iv.visitLineNumber(1, label);
490    
491            int k = isStatic ? 0 : 1;
492            for (Type argType : argTypes) {
493                iv.load(k, argType);
494                k += argType.getSize();
495            }
496            iv.invokestatic(classToDelegateTo, asmMethod.getName(), asmMethod.getDescriptor(), false);
497            iv.areturn(asmMethod.getReturnType());
498        }
499    
500        private static boolean needIndexForVar(JvmMethodParameterKind kind) {
501            return kind == JvmMethodParameterKind.CAPTURED_LOCAL_VARIABLE ||
502                   kind == JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL ||
503                   kind == JvmMethodParameterKind.SUPER_CALL_PARAM;
504        }
505    
506        public static void endVisit(MethodVisitor mv, @Nullable String description, @Nullable PsiElement method) {
507            try {
508                mv.visitMaxs(-1, -1);
509                mv.visitEnd();
510            }
511            catch (ProcessCanceledException e) {
512                throw e;
513            }
514            catch (Throwable t) {
515                String bytecode = renderByteCodeIfAvailable(mv);
516                throw new CompilationException(
517                        "wrong code generated" +
518                        (description != null ? " for " + description : "") +
519                        t.getClass().getName() +
520                        " " +
521                        t.getMessage() +
522                        (bytecode != null ? "\nbytecode:\n" + bytecode : ""),
523                        t, method);
524            }
525        }
526    
527        private static String renderByteCodeIfAvailable(MethodVisitor mv) {
528            String bytecode = null;
529    
530            if (mv instanceof OptimizationMethodVisitor) {
531                mv = ((OptimizationMethodVisitor) mv).getTraceMethodVisitorIfPossible();
532            }
533    
534            if (mv instanceof TraceMethodVisitor) {
535                TraceMethodVisitor traceMethodVisitor = (TraceMethodVisitor) mv;
536                StringWriter sw = new StringWriter();
537                PrintWriter pw = new PrintWriter(sw);
538                traceMethodVisitor.p.print(pw);
539                pw.close();
540                bytecode = sw.toString();
541            }
542            return bytecode;
543        }
544    
545        public void generateBridges(@NotNull FunctionDescriptor descriptor) {
546            if (descriptor instanceof ConstructorDescriptor) return;
547            if (owner.getContextKind() == OwnerKind.DEFAULT_IMPLS) return;
548            if (isInterface(descriptor.getContainingDeclaration())) return;
549    
550            // equals(Any?), hashCode(), toString() never need bridges
551            if (isMethodOfAny(descriptor)) return;
552    
553            // If the function doesn't have a physical declaration among super-functions, it's a SAM adapter or alike and doesn't need bridges
554            if (CallResolverUtilKt.isOrOverridesSynthesized(descriptor)) return;
555    
556            boolean isSpecial = SpecialBuiltinMembers.getOverriddenBuiltinReflectingJvmDescriptor(descriptor) != null;
557    
558            Set<Bridge<Method>> bridgesToGenerate;
559            if (!isSpecial) {
560                bridgesToGenerate = ImplKt.generateBridgesForFunctionDescriptor(
561                        descriptor,
562                        getSignatureMapper(typeMapper)
563                );
564                if (!bridgesToGenerate.isEmpty()) {
565                    PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null;
566                    boolean isSpecialBridge =
567                            BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(descriptor) != null;
568    
569                    for (Bridge<Method> bridge : bridgesToGenerate) {
570                        generateBridge(origin, descriptor, bridge.getFrom(), bridge.getTo(), isSpecialBridge, false);
571                    }
572                }
573            }
574            else {
575                Set<BridgeForBuiltinSpecial<Method>> specials = BuiltinSpecialBridgesUtil.generateBridgesForBuiltinSpecial(
576                        descriptor,
577                        getSignatureMapper(typeMapper)
578                );
579    
580                if (!specials.isEmpty()) {
581                    PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null;
582                    for (BridgeForBuiltinSpecial<Method> bridge : specials) {
583                        generateBridge(
584                                origin, descriptor, bridge.getFrom(), bridge.getTo(),
585                                bridge.isSpecial(), bridge.isDelegateToSuper());
586                    }
587                }
588    
589                if (!descriptor.getKind().isReal() && isAbstractMethod(descriptor, OwnerKind.IMPLEMENTATION)) {
590                    CallableDescriptor overridden = SpecialBuiltinMembers.getOverriddenBuiltinReflectingJvmDescriptor(descriptor);
591                    assert overridden != null;
592    
593                    Method method = typeMapper.mapSignature(descriptor).getAsmMethod();
594                    int flags = ACC_ABSTRACT | getVisibilityAccessFlag(descriptor);
595                    v.newMethod(JvmDeclarationOriginKt.OtherOrigin(overridden), flags, method.getName(), method.getDescriptor(), null, null);
596                }
597            }
598        }
599    
600        @NotNull
601        private static Function1<FunctionDescriptor, Method> getSignatureMapper(final @NotNull  JetTypeMapper typeMapper) {
602            return new Function1<FunctionDescriptor, Method>() {
603                @Override
604                public Method invoke(FunctionDescriptor descriptor) {
605                    return typeMapper.mapSignature(descriptor).getAsmMethod();
606                }
607            };
608        }
609    
610        private static boolean isMethodOfAny(@NotNull FunctionDescriptor descriptor) {
611            String name = descriptor.getName().asString();
612            List<ValueParameterDescriptor> parameters = descriptor.getValueParameters();
613            if (parameters.isEmpty()) {
614                return name.equals("hashCode") || name.equals("toString");
615            }
616            else if (parameters.size() == 1 && name.equals("equals")) {
617                return isNullableAny(parameters.get(0).getType());
618            }
619            return false;
620        }
621    
622        @NotNull
623        public static String[] getThrownExceptions(@NotNull FunctionDescriptor function, @NotNull final JetTypeMapper mapper) {
624            AnnotationDescriptor annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.throws"));
625            if (annotation == null) {
626                annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.jvm.Throws"));
627            }
628    
629            if (annotation == null) return ArrayUtil.EMPTY_STRING_ARRAY;
630    
631            Collection<ConstantValue<?>> values = annotation.getAllValueArguments().values();
632            if (values.isEmpty()) return ArrayUtil.EMPTY_STRING_ARRAY;
633    
634            Object value = values.iterator().next();
635            if (!(value instanceof ArrayValue)) return ArrayUtil.EMPTY_STRING_ARRAY;
636            ArrayValue arrayValue = (ArrayValue) value;
637    
638            List<String> strings = ContainerUtil.mapNotNull(
639                    arrayValue.getValue(),
640                    new Function<ConstantValue<?>, String>() {
641                        @Override
642                        public String fun(ConstantValue<?> constant) {
643                            if (constant instanceof KClassValue) {
644                                KClassValue classValue = (KClassValue) constant;
645                                ClassDescriptor classDescriptor = DescriptorUtils.getClassDescriptorForType(classValue.getValue());
646                                return mapper.mapClass(classDescriptor).getInternalName();
647                            }
648                            return null;
649                        }
650                    }
651            );
652            return ArrayUtil.toStringArray(strings);
653        }
654    
655        void generateDefaultIfNeeded(
656                @NotNull MethodContext owner,
657                @NotNull FunctionDescriptor functionDescriptor,
658                @NotNull OwnerKind kind,
659                @NotNull DefaultParameterValueLoader loadStrategy,
660                @Nullable KtNamedFunction function
661        ) {
662            DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration();
663    
664            if (kind != OwnerKind.DEFAULT_IMPLS && isInterface(contextClass)) {
665                return;
666            }
667    
668            if (!isDefaultNeeded(functionDescriptor)) {
669                return;
670            }
671    
672            int flags = getVisibilityAccessFlag(functionDescriptor) |
673                        getDeprecatedAccessFlag(functionDescriptor) |
674                        ACC_SYNTHETIC;
675            if (!(functionDescriptor instanceof ConstructorDescriptor)) {
676                flags |= ACC_STATIC | ACC_BRIDGE;
677            }
678            // $default methods are never private to be accessible from other class files (e.g. inner) without the need of synthetic accessors
679            flags &= ~ACC_PRIVATE;
680    
681            Method defaultMethod = typeMapper.mapDefaultMethod(functionDescriptor, kind);
682    
683            MethodVisitor mv = v.newMethod(
684                    JvmDeclarationOriginKt.Synthetic(function, functionDescriptor),
685                    flags,
686                    defaultMethod.getName(),
687                    defaultMethod.getDescriptor(), null,
688                    getThrownExceptions(functionDescriptor, typeMapper)
689            );
690    
691            // Only method annotations are copied to the $default method. Parameter annotations are not copied until there are valid use cases;
692            // enum constructors have two additional synthetic parameters which somewhat complicate this task
693            AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(functionDescriptor, defaultMethod.getReturnType());
694    
695            if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
696                if (this.owner instanceof DelegatingFacadeContext) {
697                    mv.visitCode();
698                    generateFacadeDelegateMethodBody(mv, defaultMethod, (DelegatingFacadeContext) this.owner);
699                    endVisit(mv, "default method delegation", getSourceFromDescriptor(functionDescriptor));
700                }
701                else {
702                    mv.visitCode();
703                    generateDefaultImplBody(owner, functionDescriptor, mv, loadStrategy, function, memberCodegen);
704                    endVisit(mv, "default method", getSourceFromDescriptor(functionDescriptor));
705                }
706            }
707        }
708    
709        public static void generateDefaultImplBody(
710                @NotNull MethodContext methodContext,
711                @NotNull FunctionDescriptor functionDescriptor,
712                @NotNull MethodVisitor mv,
713                @NotNull DefaultParameterValueLoader loadStrategy,
714                @Nullable KtNamedFunction function,
715                @NotNull MemberCodegen<?> parentCodegen
716        ) {
717            GenerationState state = parentCodegen.state;
718            JvmMethodSignature signature = state.getTypeMapper().mapSignature(functionDescriptor, methodContext.getContextKind());
719    
720            boolean isStatic = isStaticMethod(methodContext.getContextKind(), functionDescriptor);
721            FrameMap frameMap = createFrameMap(state, functionDescriptor, signature, isStatic);
722    
723            ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, signature.getReturnType(), methodContext, state, parentCodegen);
724    
725            CallGenerator generator = codegen.getOrCreateCallGenerator(functionDescriptor, function);
726    
727            loadExplicitArgumentsOnStack(OBJECT_TYPE, isStatic, signature, generator);
728    
729            List<JvmMethodParameterSignature> mappedParameters = signature.getValueParameters();
730            int capturedArgumentsCount = 0;
731            while (capturedArgumentsCount < mappedParameters.size() &&
732                   mappedParameters.get(capturedArgumentsCount).getKind() != JvmMethodParameterKind.VALUE) {
733                capturedArgumentsCount++;
734            }
735    
736            InstructionAdapter iv = new InstructionAdapter(mv);
737    
738            int maskIndex = 0;
739            List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters();
740            for (int index = 0; index < valueParameters.size(); index++) {
741                if (index % Integer.SIZE == 0) {
742                    maskIndex = frameMap.enterTemp(Type.INT_TYPE);
743                }
744                ValueParameterDescriptor parameterDescriptor = valueParameters.get(index);
745                Type type = mappedParameters.get(capturedArgumentsCount + index).getAsmType();
746    
747                int parameterIndex = frameMap.getIndex(parameterDescriptor);
748                if (parameterDescriptor.declaresDefaultValue()) {
749                    iv.load(maskIndex, Type.INT_TYPE);
750                    iv.iconst(1 << (index % Integer.SIZE));
751                    iv.and(Type.INT_TYPE);
752                    Label loadArg = new Label();
753                    iv.ifeq(loadArg);
754    
755                    StackValue.local(parameterIndex, type).store(loadStrategy.genValue(parameterDescriptor, codegen), iv);
756    
757                    iv.mark(loadArg);
758                }
759    
760                generator.putValueIfNeeded(parameterDescriptor, type, StackValue.local(parameterIndex, type));
761            }
762    
763            CallableMethod method = state.getTypeMapper().mapToCallableMethod(functionDescriptor, false);
764    
765            generator.genCallWithoutAssertions(method, codegen);
766    
767            iv.areturn(signature.getReturnType());
768        }
769    
770        @NotNull
771        private static FrameMap createFrameMap(
772                @NotNull GenerationState state,
773                @NotNull FunctionDescriptor function,
774                @NotNull JvmMethodSignature signature,
775                boolean isStatic
776        ) {
777            FrameMap frameMap = new FrameMap();
778            if (!isStatic) {
779                frameMap.enterTemp(OBJECT_TYPE);
780            }
781    
782            for (JvmMethodParameterSignature parameter : signature.getValueParameters()) {
783                if (parameter.getKind() == JvmMethodParameterKind.RECEIVER) {
784                    ReceiverParameterDescriptor receiverParameter = function.getExtensionReceiverParameter();
785                    if (receiverParameter != null) {
786                        frameMap.enter(receiverParameter, state.getTypeMapper().mapType(receiverParameter));
787                    }
788                }
789                else if (parameter.getKind() != JvmMethodParameterKind.VALUE) {
790                    frameMap.enterTemp(parameter.getAsmType());
791                }
792            }
793    
794            for (ValueParameterDescriptor parameter : function.getValueParameters()) {
795                frameMap.enter(parameter, state.getTypeMapper().mapType(parameter));
796            }
797    
798            return frameMap;
799        }
800    
801        private static void loadExplicitArgumentsOnStack(
802                @NotNull Type ownerType,
803                boolean isStatic,
804                @NotNull JvmMethodSignature signature,
805                @NotNull CallGenerator callGenerator
806        ) {
807            int var = 0;
808            if (!isStatic) {
809                callGenerator.putValueIfNeeded(null, ownerType, StackValue.local(var, ownerType));
810                var += ownerType.getSize();
811            }
812    
813            for (JvmMethodParameterSignature parameterSignature : signature.getValueParameters()) {
814                if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) {
815                    Type type = parameterSignature.getAsmType();
816                    callGenerator.putValueIfNeeded(null, type, StackValue.local(var, type));
817                    var += type.getSize();
818                }
819            }
820        }
821    
822        private static boolean isDefaultNeeded(FunctionDescriptor functionDescriptor) {
823            boolean needed = false;
824            if (functionDescriptor != null) {
825                for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) {
826                    if (parameterDescriptor.declaresDefaultValue()) {
827                        needed = true;
828                        break;
829                    }
830                }
831            }
832            return needed;
833        }
834    
835        private void generateBridge(
836                @Nullable PsiElement origin,
837                @NotNull FunctionDescriptor descriptor,
838                @NotNull Method bridge,
839                @NotNull Method delegateTo,
840                boolean isSpecialBridge,
841                boolean isStubDeclarationWithDelegationToSuper
842        ) {
843            boolean isSpecialOrDelegationToSuper = isSpecialBridge || isStubDeclarationWithDelegationToSuper;
844            int flags = ACC_PUBLIC | ACC_BRIDGE | (!isSpecialOrDelegationToSuper ? ACC_SYNTHETIC : 0) | (isSpecialBridge ? ACC_FINAL : 0); // TODO.
845    
846            MethodVisitor mv =
847                    v.newMethod(JvmDeclarationOriginKt.Bridge(descriptor, origin), flags, bridge.getName(), bridge.getDescriptor(), null, null);
848            if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
849    
850            mv.visitCode();
851    
852            Type[] argTypes = bridge.getArgumentTypes();
853            Type[] originalArgTypes = delegateTo.getArgumentTypes();
854    
855            InstructionAdapter iv = new InstructionAdapter(mv);
856            MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv);
857    
858            if (delegateTo.getArgumentTypes().length == 1 && isSpecialBridge) {
859                generateTypeCheckBarrierIfNeeded(iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes()[0]);
860            }
861    
862            iv.load(0, OBJECT_TYPE);
863            for (int i = 0, reg = 1; i < argTypes.length; i++) {
864                StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
865                //noinspection AssignmentToForLoopParameter
866                reg += argTypes[i].getSize();
867            }
868    
869            if (isStubDeclarationWithDelegationToSuper) {
870                ClassDescriptor parentClass = getSuperClassDescriptor((ClassDescriptor) descriptor.getContainingDeclaration());
871                assert parentClass != null;
872                String parentInternalName = typeMapper.mapClass(parentClass).getInternalName();
873                iv.invokespecial(parentInternalName, delegateTo.getName(), delegateTo.getDescriptor());
874            }
875            else {
876                iv.invokevirtual(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor());
877            }
878    
879            StackValue.coerce(delegateTo.getReturnType(), bridge.getReturnType(), iv);
880            iv.areturn(bridge.getReturnType());
881    
882            endVisit(mv, "bridge method", origin);
883        }
884    
885        private static void generateTypeCheckBarrierIfNeeded(
886                @NotNull InstructionAdapter iv,
887                @NotNull FunctionDescriptor descriptor,
888                @NotNull Type returnType,
889                @Nullable final Type delegateParameterType
890        ) {
891            BuiltinMethodsWithSpecialGenericSignature.DefaultValue defaultValue =
892                    BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor);
893            if (defaultValue == null) return;
894    
895            assert descriptor.getValueParameters().size() == 1 : "Should be descriptor with one value parameter, but found: " + descriptor;
896    
897            boolean isCheckForAny = delegateParameterType == null || OBJECT_TYPE.equals(delegateParameterType);
898    
899            final KotlinType kotlinType = descriptor.getValueParameters().get(0).getType();
900    
901            if (isCheckForAny && TypeUtils.isNullableType(kotlinType)) return;
902    
903            iv.load(1, OBJECT_TYPE);
904    
905            Label afterBarrier = new Label();
906    
907            if (isCheckForAny) {
908                assert !TypeUtils.isNullableType(kotlinType) : "Only bridges for not-nullable types are necessary";
909                iv.ifnonnull(afterBarrier);
910            }
911            else {
912                CodegenUtilKt.generateIsCheck(iv, kotlinType.isMarkedNullable(), new Function1<InstructionAdapter, Unit>() {
913                    @Override
914                    public Unit invoke(InstructionAdapter adapter) {
915                        TypeIntrinsics.instanceOf(adapter, kotlinType, boxType(delegateParameterType));
916                        return Unit.INSTANCE;
917                    }
918                });
919                iv.ifne(afterBarrier);
920            }
921    
922            StackValue.constant(defaultValue.getValue(), returnType).put(returnType, iv);
923            iv.areturn(returnType);
924    
925            iv.visitLabel(afterBarrier);
926        }
927    
928        public void genDelegate(@NotNull FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) {
929            genDelegate(functionDescriptor, overriddenDescriptor.getOriginal(),
930                        (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(), field);
931        }
932    
933        public void genDelegate(
934                @NotNull final FunctionDescriptor delegateFunction,
935                final FunctionDescriptor delegatedTo,
936                final ClassDescriptor toClass,
937                final StackValue field
938        ) {
939            generateMethod(
940                    JvmDeclarationOriginKt.Delegation(DescriptorToSourceUtils.descriptorToDeclaration(delegatedTo), delegateFunction), delegateFunction,
941                    new FunctionGenerationStrategy() {
942                        @Override
943                        public void generateBody(
944                                @NotNull MethodVisitor mv,
945                                @NotNull FrameMap frameMap,
946                                @NotNull JvmMethodSignature signature,
947                                @NotNull MethodContext context,
948                                @NotNull MemberCodegen<?> parentCodegen
949                        ) {
950                            Method delegateToMethod = typeMapper.mapSignature(delegatedTo).getAsmMethod();
951                            Method delegateMethod = typeMapper.mapSignature(delegateFunction).getAsmMethod();
952    
953                            Type[] argTypes = delegateMethod.getArgumentTypes();
954                            Type[] originalArgTypes = delegateToMethod.getArgumentTypes();
955    
956                            InstructionAdapter iv = new InstructionAdapter(mv);
957                            iv.load(0, OBJECT_TYPE);
958                            field.put(field.type, iv);
959                            for (int i = 0, reg = 1; i < argTypes.length; i++) {
960                                StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
961                                //noinspection AssignmentToForLoopParameter
962                                reg += argTypes[i].getSize();
963                            }
964    
965                            String internalName = typeMapper.mapType(toClass).getInternalName();
966                            if (toClass.getKind() == ClassKind.INTERFACE) {
967                                iv.invokeinterface(internalName, delegateToMethod.getName(), delegateToMethod.getDescriptor());
968                            }
969                            else {
970                                iv.invokevirtual(internalName, delegateToMethod.getName(), delegateToMethod.getDescriptor());
971                            }
972    
973                            StackValue stackValue = AsmUtil.genNotNullAssertions(
974                                    state,
975                                    StackValue.onStack(delegateToMethod.getReturnType()),
976                                    RuntimeAssertionInfo.create(
977                                            delegateFunction.getReturnType(),
978                                            delegatedTo.getReturnType(),
979                                            new RuntimeAssertionInfo.DataFlowExtras.OnlyMessage(delegatedTo.getName() + "(...)")
980                                    )
981                            );
982    
983                            stackValue.put(delegateMethod.getReturnType(), iv);
984    
985                            iv.areturn(delegateMethod.getReturnType());
986                        }
987                    }
988            );
989        }
990    }