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