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