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