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