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