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