001    /*
002    /*
003     * Copyright 2010-2013 JetBrains s.r.o.
004     *
005     * Licensed under the Apache License, Version 2.0 (the "License");
006     * you may not use this file except in compliance with the License.
007     * You may obtain a copy of the License at
008     *
009     * http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.jetbrains.jet.codegen;
019    
020    import com.intellij.openapi.progress.ProcessCanceledException;
021    import com.intellij.psi.PsiElement;
022    import jet.runtime.typeinfo.JetValueParameter;
023    import org.jetbrains.annotations.NotNull;
024    import org.jetbrains.annotations.Nullable;
025    import org.jetbrains.asm4.AnnotationVisitor;
026    import org.jetbrains.asm4.Label;
027    import org.jetbrains.asm4.MethodVisitor;
028    import org.jetbrains.asm4.Type;
029    import org.jetbrains.asm4.commons.InstructionAdapter;
030    import org.jetbrains.asm4.commons.Method;
031    import org.jetbrains.asm4.util.TraceMethodVisitor;
032    import org.jetbrains.jet.codegen.binding.CodegenBinding;
033    import org.jetbrains.jet.codegen.context.CodegenContext;
034    import org.jetbrains.jet.codegen.context.MethodContext;
035    import org.jetbrains.jet.codegen.context.PackageFacadeContext;
036    import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind;
037    import org.jetbrains.jet.codegen.signature.JvmMethodParameterSignature;
038    import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
039    import org.jetbrains.jet.codegen.state.GenerationState;
040    import org.jetbrains.jet.codegen.state.JetTypeMapper;
041    import org.jetbrains.jet.lang.descriptors.*;
042    import org.jetbrains.jet.lang.psi.JetNamedFunction;
043    import org.jetbrains.jet.lang.resolve.BindingContext;
044    import org.jetbrains.jet.lang.resolve.java.JvmAbi;
045    
046    import java.io.PrintWriter;
047    import java.io.StringWriter;
048    import java.util.*;
049    
050    import static org.jetbrains.asm4.Opcodes.*;
051    import static org.jetbrains.jet.codegen.AsmUtil.*;
052    import static org.jetbrains.jet.codegen.CodegenUtil.isCallInsideSameClassAsDeclared;
053    import static org.jetbrains.jet.codegen.CodegenUtil.isCallInsideSameModuleAsDeclared;
054    import static org.jetbrains.jet.codegen.JvmSerializationBindings.*;
055    import static org.jetbrains.jet.codegen.binding.CodegenBinding.asmTypeForAnonymousClass;
056    import static org.jetbrains.jet.codegen.binding.CodegenBinding.isLocalNamedFun;
057    import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration;
058    import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration;
059    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isFunctionLiteral;
060    import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
061    import static org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils.fqNameByClass;
062    
063    public class FunctionCodegen extends ParentCodegenAwareImpl {
064        private final CodegenContext owner;
065    
066        private final ClassBuilder v;
067    
068        public FunctionCodegen(@NotNull CodegenContext owner, @NotNull ClassBuilder v, @NotNull GenerationState state, MemberCodegen parentCodegen) {
069            super(state, parentCodegen);
070            this.owner = owner;
071            this.v = v;
072        }
073    
074        public void gen(@NotNull JetNamedFunction function) {
075            SimpleFunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, function);
076            assert functionDescriptor != null : "No descriptor for function " + function.getText() + "\n" +
077                                                "in " + function.getContainingFile().getVirtualFile();
078    
079            OwnerKind kind = owner.getContextKind();
080            JvmMethodSignature method = typeMapper.mapSignature(functionDescriptor, true, kind);
081    
082            if (kind != OwnerKind.TRAIT_IMPL || function.getBodyExpression() != null) {
083                generateMethod(function, method, functionDescriptor,
084                               new FunctionGenerationStrategy.FunctionDefault(state, functionDescriptor, function));
085            }
086    
087            generateDefaultIfNeeded(owner.intoFunction(functionDescriptor), method, functionDescriptor, kind,
088                                    DefaultParameterValueLoader.DEFAULT);
089        }
090    
091        public void generateMethod(
092                @Nullable PsiElement origin,
093                @NotNull JvmMethodSignature jvmSignature,
094                @NotNull FunctionDescriptor functionDescriptor,
095                @NotNull FunctionGenerationStrategy strategy
096        ) {
097            generateMethod(origin, jvmSignature, functionDescriptor, owner.intoFunction(functionDescriptor), strategy);
098        }
099    
100        public void generateMethod(
101                @Nullable PsiElement origin,
102                @NotNull JvmMethodSignature jvmSignature,
103                @NotNull FunctionDescriptor functionDescriptor,
104                @NotNull MethodContext methodContext,
105                @NotNull FunctionGenerationStrategy strategy
106        ) {
107            Method asmMethod = jvmSignature.getAsmMethod();
108    
109            MethodVisitor mv = v.newMethod(origin,
110                                           getMethodAsmFlags(functionDescriptor, methodContext.getContextKind()),
111                                           asmMethod.getName(),
112                                           asmMethod.getDescriptor(),
113                                           jvmSignature.getGenericsSignature(),
114                                           null);
115    
116            if (owner instanceof PackageFacadeContext) {
117                Type ownerType = ((PackageFacadeContext) owner).getDelegateToClassType();
118                v.getSerializationBindings().put(IMPL_CLASS_NAME_FOR_CALLABLE, functionDescriptor, shortNameByAsmType(ownerType));
119            }
120            else {
121                v.getSerializationBindings().put(METHOD_FOR_FUNCTION, functionDescriptor, asmMethod);
122            }
123    
124            AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(functionDescriptor);
125    
126            generateParameterAnnotations(functionDescriptor, mv, jvmSignature);
127    
128            generateJetValueParameterAnnotations(mv, functionDescriptor, jvmSignature);
129    
130            if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES ||
131                isAbstractMethod(functionDescriptor, methodContext.getContextKind())) {
132                generateLocalVariableTable(
133                        mv,
134                        jvmSignature,
135                        functionDescriptor,
136                        getThisTypeForFunction(functionDescriptor, methodContext),
137                        new Label(),
138                        new Label(),
139                        methodContext.getContextKind()
140                );
141                return;
142            }
143    
144            generateMethodBody(mv, functionDescriptor, methodContext, jvmSignature, strategy);
145    
146            endVisit(mv, null, origin);
147    
148            generateBridgeIfNeeded(owner, state, v, jvmSignature.getAsmMethod(), functionDescriptor);
149    
150            methodContext.recordSyntheticAccessorIfNeeded(functionDescriptor, typeMapper);
151        }
152    
153        private void generateParameterAnnotations(
154                @NotNull FunctionDescriptor functionDescriptor,
155                @NotNull MethodVisitor mv,
156                @NotNull JvmMethodSignature jvmSignature
157        ) {
158            Iterator<ValueParameterDescriptor> iterator = functionDescriptor.getValueParameters().iterator();
159            List<JvmMethodParameterSignature> kotlinParameterTypes = jvmSignature.getKotlinParameterTypes();
160    
161            for (int i = 0; i < kotlinParameterTypes.size(); i++) {
162                JvmMethodParameterKind kind = kotlinParameterTypes.get(i).getKind();
163                if (kind == JvmMethodParameterKind.ENUM_NAME || kind == JvmMethodParameterKind.ENUM_ORDINAL) {
164                    markEnumConstructorParameterAsSynthetic(mv, i);
165                    continue;
166                }
167    
168                if (kind == JvmMethodParameterKind.VALUE) {
169                    ValueParameterDescriptor parameter = iterator.next();
170                    v.getSerializationBindings().put(INDEX_FOR_VALUE_PARAMETER, parameter, i);
171                    AnnotationCodegen.forParameter(i, mv, typeMapper).genAnnotations(parameter);
172                }
173            }
174        }
175    
176        @SuppressWarnings("deprecation")
177        private void generateJetValueParameterAnnotations(
178                @NotNull MethodVisitor mv,
179                @NotNull FunctionDescriptor functionDescriptor,
180                @NotNull JvmMethodSignature jvmSignature
181        ) {
182            Iterator<ValueParameterDescriptor> descriptors = functionDescriptor.getValueParameters().iterator();
183            List<JvmMethodParameterSignature> kotlinParameterTypes = jvmSignature.getKotlinParameterTypes();
184    
185            for (int i = 0; i < kotlinParameterTypes.size(); i++) {
186                JvmMethodParameterKind kind = kotlinParameterTypes.get(i).getKind();
187                if (kind == JvmMethodParameterKind.ENUM_NAME || kind == JvmMethodParameterKind.ENUM_ORDINAL) {
188                    markEnumConstructorParameterAsSynthetic(mv, i);
189                    continue;
190                }
191    
192                String name;
193                boolean nullableType;
194                if (kind == JvmMethodParameterKind.VALUE) {
195                    ValueParameterDescriptor descriptor = descriptors.next();
196                    name = descriptor.getName().asString();
197                    nullableType = descriptor.getType().isNullable();
198                }
199                else {
200                    String lowercaseKind = kind.name().toLowerCase();
201                    if (needIndexForVar(kind)) {
202                        name = "$" + lowercaseKind + "$" + i;
203                    }
204                    else {
205                        name = "$" + lowercaseKind;
206                    }
207    
208                    if (kind == JvmMethodParameterKind.RECEIVER) {
209                        ReceiverParameterDescriptor receiver = functionDescriptor.getReceiverParameter();
210                        nullableType = receiver == null || receiver.getType().isNullable();
211                    }
212                    else {
213                        nullableType = true;
214                    }
215                }
216    
217                AnnotationVisitor av =
218                        mv.visitParameterAnnotation(i, asmDescByFqNameWithoutInnerClasses(fqNameByClass(JetValueParameter.class)), true);
219                if (av != null) {
220                    av.visit("name", name);
221                    if (nullableType) {
222                        av.visit("type", "?");
223                    }
224                    av.visitEnd();
225                }
226            }
227        }
228    
229        private void markEnumConstructorParameterAsSynthetic(MethodVisitor mv, int i) {
230            // IDEA's ClsPsi builder fails to annotate synthetic parameters
231            if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return;
232    
233            // This is needed to avoid RuntimeInvisibleParameterAnnotations error in javac:
234            // see MethodWriter.visitParameterAnnotation()
235    
236            AnnotationVisitor av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", true);
237            if (av != null) {
238                av.visitEnd();
239            }
240        }
241    
242        @Nullable
243        private Type getThisTypeForFunction(@NotNull FunctionDescriptor functionDescriptor, @NotNull MethodContext context) {
244            ReceiverParameterDescriptor expectedThisObject = functionDescriptor.getExpectedThisObject();
245            if (functionDescriptor instanceof ConstructorDescriptor) {
246                return typeMapper.mapType(functionDescriptor);
247            }
248            else if (expectedThisObject != null) {
249                return typeMapper.mapType(expectedThisObject.getType());
250            }
251            else if (isFunctionLiteral(functionDescriptor) || isLocalNamedFun(functionDescriptor)) {
252                return typeMapper.mapType(context.getThisDescriptor());
253            }
254            else {
255                return null;
256            }
257        }
258    
259        private void generateMethodBody(
260                @NotNull MethodVisitor mv,
261                @NotNull FunctionDescriptor functionDescriptor,
262                @NotNull MethodContext context,
263                @NotNull JvmMethodSignature signature,
264                @NotNull FunctionGenerationStrategy strategy
265        ) {
266            mv.visitCode();
267    
268            Label methodBegin = new Label();
269            mv.visitLabel(methodBegin);
270    
271            if (context.getParentContext() instanceof PackageFacadeContext) {
272                generateStaticDelegateMethodBody(mv, signature.getAsmMethod(), (PackageFacadeContext) context.getParentContext());
273            }
274            else {
275                FrameMap frameMap = strategy.getFrameMap(typeMapper, context);
276    
277                for (ValueParameterDescriptor parameter : functionDescriptor.getValueParameters()) {
278                    frameMap.enter(parameter, typeMapper.mapType(parameter));
279                }
280    
281                Label methodEntry = new Label();
282                mv.visitLabel(methodEntry);
283                context.setMethodStartLabel(methodEntry);
284    
285                if (!JetTypeMapper.isAccessor(functionDescriptor)) {
286                    genNotNullAssertionsForParameters(new InstructionAdapter(mv), state, functionDescriptor, frameMap);
287                }
288    
289                strategy.generateBody(mv, signature, context, getParentCodegen());
290            }
291    
292            Label methodEnd = new Label();
293            mv.visitLabel(methodEnd);
294    
295    
296            Type thisType = getThisTypeForFunction(functionDescriptor, context);
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.getKotlinParameterTypes();
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 namespace 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                Method jvmSignature,
412                FunctionDescriptor functionDescriptor
413        ) {
414            if (owner.getContextKind() == OwnerKind.TRAIT_IMPL) {
415                return;
416            }
417    
418            Method method =
419                    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 =
439                            state.getTypeMapper().mapSignature(descriptor.getOriginal()).getAsmMethod();
440                    if (differentMethods(method, overridden)) {
441                        bridgesToGenerate.add(overridden);
442                    }
443                    continue;
444                }
445    
446                for (FunctionDescriptor overriddenDescriptor : descriptor.getOverriddenDescriptors()) {
447                    FunctionDescriptor orig = overriddenDescriptor.getOriginal();
448                    if (!visited.contains(orig)) {
449                        bfsQueue.offer(orig);
450                        visited.add(orig);
451                    }
452                }
453            }
454    
455            for (Method overridden : bridgesToGenerate) {
456                generateBridge(state, v, jvmSignature, functionDescriptor, overridden);
457            }
458        }
459    
460        static void generateConstructorWithoutParametersIfNeeded(
461                @NotNull GenerationState state,
462                @NotNull CallableMethod method,
463                @NotNull ConstructorDescriptor constructorDescriptor,
464                @NotNull ClassBuilder classBuilder
465        ) {
466            if (!isDefaultConstructorNeeded(state.getBindingContext(), constructorDescriptor)) {
467                return;
468            }
469            int flags = getVisibilityAccessFlag(constructorDescriptor);
470            MethodVisitor mv = classBuilder.newMethod(null, flags, "<init>", "()V", null, null);
471    
472            if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) {
473                return;
474            }
475            else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
476                InstructionAdapter v = new InstructionAdapter(mv);
477                mv.visitCode();
478    
479                Type methodOwner = method.getOwner();
480                Method jvmSignature = method.getSignature().getAsmMethod();
481                v.load(0, methodOwner); // Load this on stack
482    
483                int mask = 0;
484                for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
485                    Type paramType = state.getTypeMapper().mapType(parameterDescriptor.getType());
486                    pushDefaultValueOnStack(paramType, v);
487                    mask |= (1 << parameterDescriptor.getIndex());
488                }
489                v.iconst(mask);
490                String desc = jvmSignature.getDescriptor().replace(")", "I)");
491                v.invokespecial(methodOwner.getInternalName(), "<init>", desc);
492                v.areturn(Type.VOID_TYPE);
493                endVisit(mv, "default constructor for " + methodOwner.getInternalName(), null);
494            }
495        }
496    
497        void generateDefaultIfNeeded(
498                @NotNull MethodContext owner,
499                @NotNull JvmMethodSignature signature,
500                @NotNull FunctionDescriptor functionDescriptor,
501                @NotNull OwnerKind kind,
502                @NotNull DefaultParameterValueLoader loadStrategy
503        ) {
504            DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration();
505    
506            if (kind != OwnerKind.TRAIT_IMPL &&
507                contextClass instanceof ClassDescriptor &&
508                ((ClassDescriptor) contextClass).getKind() == ClassKind.TRAIT) {
509                return;
510            }
511    
512            if (!isDefaultNeeded(functionDescriptor)) {
513                return;
514            }
515    
516            boolean isStatic = isStatic(kind);
517    
518            Method jvmSignature = signature.getAsmMethod();
519    
520            int flags = ACC_PUBLIC | ACC_SYNTHETIC; // TODO.
521    
522            Type ownerType;
523            if (contextClass instanceof PackageFragmentDescriptor) {
524                ownerType = state.getTypeMapper().getOwner(functionDescriptor, kind, true);
525            }
526            else if (contextClass instanceof ClassDescriptor) {
527                ownerType = state.getTypeMapper().mapClass((ClassDescriptor) contextClass);
528            }
529            else if (isLocalNamedFun(functionDescriptor)) {
530                ownerType = asmTypeForAnonymousClass(state.getBindingContext(), functionDescriptor);
531            }
532            else {
533                throw new IllegalStateException("Couldn't obtain owner name for " + functionDescriptor);
534            }
535    
536            String descriptor = jvmSignature.getDescriptor().replace(")", "I)");
537            boolean isConstructor = "<init>".equals(jvmSignature.getName());
538            if (!isStatic && !isConstructor) {
539                descriptor = descriptor.replace("(", "(" + ownerType.getDescriptor());
540            }
541            MethodVisitor mv = v.newMethod(null, flags | (isConstructor ? 0 : ACC_STATIC),
542                                           isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX,
543                                           descriptor, null, null);
544    
545            if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
546                generateDefaultImpl(owner, signature, functionDescriptor, isStatic, mv, loadStrategy);
547    
548            }
549        }
550    
551        private void generateDefaultImpl(
552                @NotNull MethodContext methodContext,
553                @NotNull JvmMethodSignature signature,
554                @NotNull FunctionDescriptor functionDescriptor,
555                boolean aStatic,
556                @NotNull MethodVisitor mv,
557                @NotNull DefaultParameterValueLoader loadStrategy
558        ) {
559            mv.visitCode();
560    
561            FrameMap frameMap = new FrameMap();
562    
563            if (!aStatic) {
564                frameMap.enterTemp(OBJECT_TYPE);
565            }
566    
567            Method jvmSignature = signature.getAsmMethod();
568            ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), methodContext, state, getParentCodegen());
569    
570            Type[] argTypes = jvmSignature.getArgumentTypes();
571            List<ValueParameterDescriptor> paramDescrs = functionDescriptor.getValueParameters();
572            Iterator<ValueParameterDescriptor> iterator = paramDescrs.iterator();
573    
574            int countOfExtraVarsInMethodArgs = 0;
575    
576            for (JvmMethodParameterSignature parameterSignature : signature.getKotlinParameterTypes()) {
577                if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) {
578                    countOfExtraVarsInMethodArgs++;
579                    frameMap.enterTemp(parameterSignature.getAsmType());
580                }
581                else {
582                    frameMap.enter(iterator.next(), parameterSignature.getAsmType());
583                }
584            }
585    
586            int maskIndex = frameMap.enterTemp(Type.INT_TYPE);
587    
588            InstructionAdapter iv = new InstructionAdapter(mv);
589            loadExplicitArgumentsOnStack(iv, OBJECT_TYPE, aStatic, signature);
590    
591            for (int index = 0; index < paramDescrs.size(); index++) {
592                ValueParameterDescriptor parameterDescriptor = paramDescrs.get(index);
593    
594                Type t = argTypes[countOfExtraVarsInMethodArgs + index];
595    
596                if (parameterDescriptor.declaresDefaultValue()) {
597                    iv.load(maskIndex, Type.INT_TYPE);
598                    iv.iconst(1 << index);
599                    iv.and(Type.INT_TYPE);
600                    Label loadArg = new Label();
601                    iv.ifeq(loadArg);
602    
603                    loadStrategy.putValueOnStack(parameterDescriptor, codegen);
604    
605                    int ind = frameMap.getIndex(parameterDescriptor);
606                    iv.store(ind, t);
607    
608                    iv.mark(loadArg);
609                }
610    
611                iv.load(frameMap.getIndex(parameterDescriptor), t);
612            }
613    
614            CallableMethod method;
615            if (functionDescriptor instanceof ConstructorDescriptor) {
616                method = state.getTypeMapper().mapToCallableMethod((ConstructorDescriptor) functionDescriptor);
617            } else {
618                method = state.getTypeMapper()
619                        .mapToCallableMethod(functionDescriptor, false, isCallInsideSameClassAsDeclared(functionDescriptor, methodContext),
620                                             isCallInsideSameModuleAsDeclared(functionDescriptor, methodContext), OwnerKind.IMPLEMENTATION);
621            }
622    
623            iv.visitMethodInsn(method.getInvokeOpcode(), method.getOwner().getInternalName(), method.getSignature().getAsmMethod().getName(),
624                               method.getSignature().getAsmMethod().getDescriptor());
625    
626            iv.areturn(jvmSignature.getReturnType());
627    
628            endVisit(mv, "default method", callableDescriptorToDeclaration(state.getBindingContext(), functionDescriptor));
629        }
630    
631    
632        private static void loadExplicitArgumentsOnStack(
633                @NotNull InstructionAdapter iv,
634                @NotNull Type ownerType,
635                boolean isStatic,
636                @NotNull JvmMethodSignature signature
637        ) {
638            int var = 0;
639            if (!isStatic) {
640                iv.load(var, ownerType);
641                var += ownerType.getSize();
642            }
643    
644            for (JvmMethodParameterSignature parameterSignature : signature.getKotlinParameterTypes()) {
645                if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) {
646                    Type type = parameterSignature.getAsmType();
647                    iv.load(var, type);
648                    var += type.getSize();
649                }
650            }
651        }
652    
653        private static boolean isDefaultNeeded(FunctionDescriptor functionDescriptor) {
654            boolean needed = false;
655            if (functionDescriptor != null) {
656                for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) {
657                    if (parameterDescriptor.declaresDefaultValue()) {
658                        needed = true;
659                        break;
660                    }
661                }
662            }
663            return needed;
664        }
665    
666        private static boolean isDefaultConstructorNeeded(@NotNull BindingContext context, @NotNull ConstructorDescriptor constructorDescriptor) {
667            ClassDescriptor classDescriptor = constructorDescriptor.getContainingDeclaration();
668    
669            if (CodegenBinding.canHaveOuter(context, classDescriptor)) return false;
670    
671            if (classDescriptor.getVisibility() == Visibilities.PRIVATE ||
672                constructorDescriptor.getVisibility() == Visibilities.PRIVATE) return false;
673    
674            if (constructorDescriptor.getValueParameters().isEmpty()) return false;
675    
676            for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
677                if (!parameterDescriptor.declaresDefaultValue()) {
678                    return false;
679                }
680            }
681            return true;
682        }
683    
684        private static boolean differentMethods(Method method, Method overridden) {
685            if (!method.getReturnType().equals(overridden.getReturnType())) {
686                return true;
687            }
688            Type[] methodArgumentTypes = method.getArgumentTypes();
689            Type[] overriddenArgumentTypes = overridden.getArgumentTypes();
690            if (methodArgumentTypes.length != overriddenArgumentTypes.length) {
691                return true;
692            }
693            for (int i = 0; i != methodArgumentTypes.length; ++i) {
694                if (!methodArgumentTypes[i].equals(overriddenArgumentTypes[i])) {
695                    return true;
696                }
697            }
698            return false;
699        }
700    
701        private static void generateBridge(
702                GenerationState state,
703                ClassBuilder v,
704                Method jvmSignature,
705                FunctionDescriptor functionDescriptor,
706                Method overridden
707        ) {
708            int flags = ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC; // TODO.
709    
710            MethodVisitor mv = v.newMethod(null, flags, jvmSignature.getName(), overridden.getDescriptor(), null, null);
711            if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
712                mv.visitCode();
713    
714                Type[] argTypes = overridden.getArgumentTypes();
715                Type[] originalArgTypes = jvmSignature.getArgumentTypes();
716    
717                InstructionAdapter iv = new InstructionAdapter(mv);
718                iv.load(0, OBJECT_TYPE);
719                for (int i = 0, reg = 1; i < argTypes.length; i++) {
720                    StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
721                    //noinspection AssignmentToForLoopParameter
722                    reg += argTypes[i].getSize();
723                }
724    
725                iv.invokevirtual(v.getThisName(), jvmSignature.getName(), jvmSignature.getDescriptor());
726    
727                StackValue.onStack(jvmSignature.getReturnType()).put(overridden.getReturnType(), iv);
728    
729                iv.areturn(overridden.getReturnType());
730                endVisit(mv, "bridge method", callableDescriptorToDeclaration(state.getBindingContext(), functionDescriptor));
731            }
732        }
733    
734        public void genDelegate(FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) {
735            genDelegate(functionDescriptor, (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(), field,
736                        typeMapper.mapSignature(functionDescriptor),
737                        typeMapper.mapSignature(overriddenDescriptor.getOriginal())
738            );
739        }
740    
741        public void genDelegate(
742                FunctionDescriptor functionDescriptor,
743                ClassDescriptor toClass,
744                StackValue field,
745                JvmMethodSignature jvmDelegateMethodSignature,
746                JvmMethodSignature jvmOverriddenMethodSignature
747        ) {
748            Method overriddenMethod = jvmOverriddenMethodSignature.getAsmMethod();
749            Method delegateMethod = jvmDelegateMethodSignature.getAsmMethod();
750    
751            int flags = ACC_PUBLIC | ACC_SYNTHETIC; // TODO.
752    
753            MethodVisitor mv = v.newMethod(null, flags, delegateMethod.getName(), delegateMethod.getDescriptor(), null, null);
754            if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
755                mv.visitCode();
756    
757                Type[] argTypes = delegateMethod.getArgumentTypes();
758                Type[] originalArgTypes = overriddenMethod.getArgumentTypes();
759    
760                InstructionAdapter iv = new InstructionAdapter(mv);
761                iv.load(0, OBJECT_TYPE);
762                field.put(field.type, iv);
763                for (int i = 0, reg = 1; i < argTypes.length; i++) {
764                    StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
765                    //noinspection AssignmentToForLoopParameter
766                    reg += argTypes[i].getSize();
767                }
768    
769                String internalName = typeMapper.mapType(toClass).getInternalName();
770                if (toClass.getKind() == ClassKind.TRAIT) {
771                    iv.invokeinterface(internalName, overriddenMethod.getName(), overriddenMethod.getDescriptor());
772                }
773                else {
774                    iv.invokevirtual(internalName, overriddenMethod.getName(), overriddenMethod.getDescriptor());
775                }
776    
777                StackValue.onStack(overriddenMethod.getReturnType()).put(delegateMethod.getReturnType(), iv);
778    
779                iv.areturn(delegateMethod.getReturnType());
780                endVisit(mv, "Delegate method " + functionDescriptor + " to " + jvmOverriddenMethodSignature,
781                         descriptorToDeclaration(bindingContext, functionDescriptor.getContainingDeclaration()));
782    
783                generateBridgeIfNeeded(owner, state, v, jvmDelegateMethodSignature.getAsmMethod(), functionDescriptor);
784            }
785        }
786    }