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