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