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