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