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