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