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