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