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