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