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