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