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