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