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