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