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