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
017package org.jetbrains.jet.codegen;
018
019import com.intellij.openapi.progress.ProcessCanceledException;
020import com.intellij.psi.PsiElement;
021import org.jetbrains.annotations.NotNull;
022import org.jetbrains.annotations.Nullable;
023import org.jetbrains.asm4.AnnotationVisitor;
024import org.jetbrains.asm4.Label;
025import org.jetbrains.asm4.MethodVisitor;
026import org.jetbrains.asm4.Type;
027import org.jetbrains.asm4.commons.InstructionAdapter;
028import org.jetbrains.asm4.commons.Method;
029import org.jetbrains.jet.codegen.binding.CodegenBinding;
030import org.jetbrains.jet.codegen.context.CodegenContext;
031import org.jetbrains.jet.codegen.context.MethodContext;
032import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind;
033import org.jetbrains.jet.codegen.signature.JvmMethodParameterSignature;
034import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
035import org.jetbrains.jet.codegen.signature.JvmPropertyAccessorSignature;
036import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter;
037import org.jetbrains.jet.codegen.signature.kotlin.JetValueParameterAnnotationWriter;
038import org.jetbrains.jet.codegen.state.GenerationState;
039import org.jetbrains.jet.codegen.state.GenerationStateAware;
040import org.jetbrains.jet.codegen.state.JetTypeMapper;
041import org.jetbrains.jet.codegen.state.JetTypeMapperMode;
042import org.jetbrains.jet.lang.descriptors.*;
043import org.jetbrains.jet.lang.psi.JetNamedFunction;
044import org.jetbrains.jet.lang.resolve.BindingContext;
045import org.jetbrains.jet.lang.resolve.java.JvmAbi;
046import org.jetbrains.jet.lang.resolve.java.JvmClassName;
047import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
048import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils;
049import org.jetbrains.jet.lang.resolve.name.Name;
050
051import java.util.*;
052
053import static org.jetbrains.asm4.Opcodes.*;
054import static org.jetbrains.jet.codegen.AsmUtil.*;
055import static org.jetbrains.jet.codegen.CodegenUtil.*;
056import static org.jetbrains.jet.codegen.binding.CodegenBinding.isLocalNamedFun;
057import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration;
058import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration;
059import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isFunctionLiteral;
060import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
061
062public 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        Iterator<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters().iterator();
373        List<JvmMethodParameterSignature> kotlinParameterTypes = jvmSignature.getKotlinParameterTypes();
374
375        assert kotlinParameterTypes != null;
376
377        for (int i = 0; i < kotlinParameterTypes.size(); i++) {
378            JvmMethodParameterSignature param =  kotlinParameterTypes.get(i);
379            JvmMethodParameterKind kind = param.getKind();
380            String parameterName = "$" + param.getKind().name().toLowerCase();
381
382            ValueParameterDescriptor parameterDescriptor = null;
383            if (kind == JvmMethodParameterKind.VALUE) {
384                parameterDescriptor = valueParameters.next();
385                parameterName = parameterDescriptor.getName().asString();
386            } else if (kind == JvmMethodParameterKind.ENUM_NAME || kind == JvmMethodParameterKind.ENUM_ORDINAL) {
387                //we shouldn't generate annotations for invisible in runtime parameters otherwise we get bad RuntimeInvisibleParameterAnnotations error in javac
388                continue;
389            } else if (needIndexForVar(kind)) {
390                parameterName = parameterName + "$" + i;
391            }
392
393            AnnotationCodegen.forParameter(i, mv, typeMapper).genAnnotations(parameterDescriptor);
394            JetValueParameterAnnotationWriter av = JetValueParameterAnnotationWriter.visitParameterAnnotation(mv, i);
395            av.writeName(parameterName);
396            if (kind == JvmMethodParameterKind.RECEIVER) {
397                av.writeReceiver();
398            }
399            if (parameterDescriptor != null) {
400                av.writeHasDefaultValue(parameterDescriptor.declaresDefaultValue());
401                av.writeVararg(parameterDescriptor.getVarargElementType() != null);
402            }
403            av.writeType(param.getKotlinSignature());
404            av.visitEnd();
405        }
406    }
407
408    private boolean needIndexForVar(JvmMethodParameterKind kind) {
409        return kind == JvmMethodParameterKind.SHARED_VAR || kind == JvmMethodParameterKind.SUPER_CALL_PARAM;
410    }
411
412    public static void endVisit(MethodVisitor mv, @Nullable String description, @Nullable PsiElement method) {
413        try {
414            mv.visitMaxs(-1, -1);
415        }
416        catch (ProcessCanceledException e) {
417            throw e;
418        }
419        catch (Throwable t) {
420            throw new CompilationException(
421                    "wrong code generated" +
422                    (description != null ? " for " + description : "") +
423                    t.getClass().getName() +
424                    " " +
425                    t.getMessage(),
426                    t, method);
427        }
428        mv.visitEnd();
429    }
430
431    static void generateBridgeIfNeeded(
432            CodegenContext owner,
433            GenerationState state,
434            ClassBuilder v,
435            Method jvmSignature,
436            FunctionDescriptor functionDescriptor
437    ) {
438        if (owner.getContextKind() == OwnerKind.TRAIT_IMPL) {
439            return;
440        }
441
442        Method method =
443                state.getTypeMapper().mapSignature(functionDescriptor).getAsmMethod();
444
445        Queue<FunctionDescriptor> bfsQueue = new LinkedList<FunctionDescriptor>();
446        Set<FunctionDescriptor> visited = new HashSet<FunctionDescriptor>();
447
448        bfsQueue.offer(functionDescriptor.getOriginal());
449        visited.add(functionDescriptor.getOriginal());
450        for (FunctionDescriptor overriddenDescriptor : functionDescriptor.getOverriddenDescriptors()) {
451            FunctionDescriptor orig = overriddenDescriptor.getOriginal();
452            if (!visited.contains(orig)) {
453                bfsQueue.offer(overriddenDescriptor);
454                visited.add(overriddenDescriptor);
455            }
456        }
457
458        Set<Method> bridgesToGenerate = new HashSet<Method>();
459        while (!bfsQueue.isEmpty()) {
460            FunctionDescriptor descriptor = bfsQueue.poll();
461            if (descriptor.getKind() == CallableMemberDescriptor.Kind.DECLARATION) {
462                Method overridden =
463                        state.getTypeMapper().mapSignature(descriptor.getOriginal()).getAsmMethod();
464                if (differentMethods(method, overridden)) {
465                    bridgesToGenerate.add(overridden);
466                }
467                continue;
468            }
469
470            for (FunctionDescriptor overriddenDescriptor : descriptor.getOverriddenDescriptors()) {
471                FunctionDescriptor orig = overriddenDescriptor.getOriginal();
472                if (!visited.contains(orig)) {
473                    bfsQueue.offer(orig);
474                    visited.add(orig);
475                }
476            }
477        }
478
479        for (Method overridden : bridgesToGenerate) {
480            generateBridge(owner, state, v, jvmSignature, functionDescriptor, overridden);
481        }
482    }
483
484    static void generateConstructorWithoutParametersIfNeeded(
485            @NotNull GenerationState state,
486            @NotNull CallableMethod method,
487            @NotNull ConstructorDescriptor constructorDescriptor,
488            @NotNull ClassBuilder classBuilder
489    ) {
490        if (!isDefaultConstructorNeeded(state.getBindingContext(), constructorDescriptor)) {
491            return;
492        }
493        int flags = getVisibilityAccessFlag(constructorDescriptor);
494        MethodVisitor mv = classBuilder.newMethod(null, flags, "<init>", "()V", null, null);
495
496        if (state.getClassBuilderMode() == ClassBuilderMode.SIGNATURES) {
497            return;
498        }
499        else if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
500            genStubCode(mv);
501        }
502        else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
503            InstructionAdapter v = new InstructionAdapter(mv);
504            mv.visitCode();
505
506            JvmClassName ownerInternalName = method.getOwner();
507            Method jvmSignature = method.getSignature().getAsmMethod();
508            v.load(0, ownerInternalName.getAsmType()); // Load this on stack
509
510            int mask = 0;
511            for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
512                Type paramType = state.getTypeMapper().mapType(parameterDescriptor.getType());
513                pushDefaultValueOnStack(paramType, v);
514                mask |= (1 << parameterDescriptor.getIndex());
515            }
516            v.iconst(mask);
517            String desc = jvmSignature.getDescriptor().replace(")", "I)");
518            v.invokespecial(ownerInternalName.getInternalName(), "<init>", desc);
519            v.areturn(Type.VOID_TYPE);
520            endVisit(mv, "default constructor for " + ownerInternalName.getInternalName(), null);
521        }
522    }
523
524    static void generateDefaultIfNeeded(
525            @NotNull MethodContext owner,
526            @NotNull GenerationState state,
527            @NotNull ClassBuilder v,
528            @NotNull JvmMethodSignature signature,
529            @NotNull FunctionDescriptor functionDescriptor,
530            @NotNull OwnerKind kind,
531            @NotNull DefaultParameterValueLoader loadStrategy
532    ) {
533        DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration();
534
535        if (kind != OwnerKind.TRAIT_IMPL &&
536            contextClass instanceof ClassDescriptor &&
537            ((ClassDescriptor) contextClass).getKind() == ClassKind.TRAIT) {
538            return;
539        }
540
541        if (!isDefaultNeeded(functionDescriptor)) {
542            return;
543        }
544
545        boolean isStatic = isStatic(kind);
546
547        Method jvmSignature = signature.getAsmMethod();
548
549        int flags = ACC_PUBLIC | ACC_SYNTHETIC; // TODO.
550
551        JvmClassName ownerInternalName;
552        if (contextClass instanceof NamespaceDescriptor) {
553            ownerInternalName = state.getTypeMapper().getOwner(functionDescriptor, kind, true);
554        }
555        else {
556            ownerInternalName = JvmClassName.byType(state.getTypeMapper()
557                                                            .mapType(((ClassDescriptor) contextClass).getDefaultType(),
558                                                                     JetTypeMapperMode.IMPL));
559        }
560
561        String descriptor = jvmSignature.getDescriptor().replace(")", "I)");
562        boolean isConstructor = "<init>".equals(jvmSignature.getName());
563        if (!isStatic && !isConstructor) {
564            descriptor = descriptor.replace("(", "(" + ownerInternalName.getDescriptor());
565        }
566        MethodVisitor mv = v.newMethod(null, flags | (isConstructor ? 0 : ACC_STATIC),
567                                             isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX,
568                                             descriptor, null, null);
569
570        if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
571            genStubCode(mv);
572        }
573        else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
574            generateDefaultImpl(owner, state, signature, functionDescriptor, kind, isStatic, mv, loadStrategy);
575        }
576    }
577
578    private static void generateDefaultImpl(
579            @NotNull MethodContext methodContext,
580            @NotNull GenerationState state,
581            @NotNull JvmMethodSignature signature,
582            @NotNull FunctionDescriptor functionDescriptor,
583            @NotNull OwnerKind kind,
584            boolean aStatic,
585            @NotNull MethodVisitor mv,
586            @NotNull DefaultParameterValueLoader loadStrategy
587    ) {
588        mv.visitCode();
589
590        FrameMap frameMap = new FrameMap();
591
592        if (!aStatic) {
593            frameMap.enterTemp(OBJECT_TYPE);
594        }
595
596        Method jvmSignature = signature.getAsmMethod();
597        ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), methodContext, state);
598
599        Type[] argTypes = jvmSignature.getArgumentTypes();
600        List<ValueParameterDescriptor> paramDescrs = functionDescriptor.getValueParameters();
601        Iterator<ValueParameterDescriptor> iterator = paramDescrs.iterator();
602
603        int countOfExtraVarsInMethodArgs = 0;
604        List<JvmMethodParameterSignature> params = signature.getKotlinParameterTypes();
605
606        for (int i = 0; i < params.size(); i++) {
607            JvmMethodParameterSignature parameterSignature = params.get(i);
608            if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) {
609                countOfExtraVarsInMethodArgs++;
610                frameMap.enterTemp(parameterSignature.getAsmType());
611            } else {
612                frameMap.enter(iterator.next(), parameterSignature.getAsmType());
613            }
614        }
615
616        int maskIndex = frameMap.enterTemp(Type.INT_TYPE);
617
618        InstructionAdapter iv = new InstructionAdapter(mv);
619        loadExplicitArgumentsOnStack(iv, OBJECT_TYPE, aStatic, signature);
620
621        for (int index = 0; index < paramDescrs.size(); index++) {
622            ValueParameterDescriptor parameterDescriptor = paramDescrs.get(index);
623
624            Type t = argTypes[countOfExtraVarsInMethodArgs + index];
625
626            if (parameterDescriptor.declaresDefaultValue()) {
627                iv.load(maskIndex, Type.INT_TYPE);
628                iv.iconst(1 << index);
629                iv.and(Type.INT_TYPE);
630                Label loadArg = new Label();
631                iv.ifeq(loadArg);
632
633                loadStrategy.putValueOnStack(parameterDescriptor, codegen);
634
635                int ind = frameMap.getIndex(parameterDescriptor);
636                iv.store(ind, t);
637
638                iv.mark(loadArg);
639            }
640
641            iv.load(frameMap.getIndex(parameterDescriptor), t);
642        }
643
644        CallableMethod method = null;
645        if (functionDescriptor instanceof ConstructorDescriptor) {
646            method = state.getTypeMapper().mapToCallableMethod((ConstructorDescriptor) functionDescriptor);
647        } else {
648            method = state.getTypeMapper()
649                    .mapToCallableMethod(functionDescriptor, false, isCallInsideSameClassAsDeclared(functionDescriptor, methodContext),
650                                         isCallInsideSameModuleAsDeclared(functionDescriptor, methodContext), OwnerKind.IMPLEMENTATION);
651        }
652
653        iv.visitMethodInsn(method.getInvokeOpcode(), method.getOwner().getInternalName(), method.getSignature().getAsmMethod().getName(),
654                           method.getSignature().getAsmMethod().getDescriptor());
655
656        iv.areturn(jvmSignature.getReturnType());
657
658        endVisit(mv, "default method", callableDescriptorToDeclaration(state.getBindingContext(), functionDescriptor));
659        mv.visitEnd();
660    }
661
662
663    private static void loadExplicitArgumentsOnStack(
664            @NotNull InstructionAdapter iv,
665            @NotNull Type ownerType,
666            boolean isStatic,
667            @NotNull JvmMethodSignature signature
668    ) {
669        int var = 0;
670        if (!isStatic) {
671            iv.load(var, ownerType);
672            var += ownerType.getSize();
673        }
674
675        List<JvmMethodParameterSignature> params = signature.getKotlinParameterTypes();
676        for (int i = 0; i < params.size(); i++) {
677            JvmMethodParameterSignature parameterSignature = params.get(i);
678            if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) {
679                Type type = parameterSignature.getAsmType();
680                iv.load(var, type);
681                var += type.getSize();
682            }
683        }
684    }
685
686    private static boolean isDefaultNeeded(FunctionDescriptor functionDescriptor) {
687        boolean needed = false;
688        if (functionDescriptor != null) {
689            for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) {
690                if (parameterDescriptor.declaresDefaultValue()) {
691                    needed = true;
692                    break;
693                }
694            }
695        }
696        return needed;
697    }
698
699    private static boolean isDefaultConstructorNeeded(@NotNull BindingContext context, @NotNull ConstructorDescriptor constructorDescriptor) {
700        ClassDescriptor classDescriptor = constructorDescriptor.getContainingDeclaration();
701
702        if (CodegenBinding.canHaveOuter(context, classDescriptor)) return false;
703
704        if (classDescriptor.getVisibility() == Visibilities.PRIVATE ||
705            constructorDescriptor.getVisibility() == Visibilities.PRIVATE) return false;
706
707        if (constructorDescriptor.getValueParameters().isEmpty()) return false;
708
709        for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
710            if (!parameterDescriptor.declaresDefaultValue()) {
711                return false;
712            }
713        }
714        return true;
715    }
716
717    private static boolean differentMethods(Method method, Method overridden) {
718        if (!method.getReturnType().equals(overridden.getReturnType())) {
719            return true;
720        }
721        Type[] methodArgumentTypes = method.getArgumentTypes();
722        Type[] overriddenArgumentTypes = overridden.getArgumentTypes();
723        if (methodArgumentTypes.length != overriddenArgumentTypes.length) {
724            return true;
725        }
726        for (int i = 0; i != methodArgumentTypes.length; ++i) {
727            if (!methodArgumentTypes[i].equals(overriddenArgumentTypes[i])) {
728                return true;
729            }
730        }
731        return false;
732    }
733
734    private static void generateBridge(
735            CodegenContext owner,
736            GenerationState state,
737            ClassBuilder v,
738            Method jvmSignature,
739            FunctionDescriptor functionDescriptor,
740            Method overridden
741    ) {
742        int flags = ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC; // TODO.
743
744        MethodVisitor mv = v.newMethod(null, flags, jvmSignature.getName(), overridden.getDescriptor(), null, null);
745        if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
746            genStubCode(mv);
747        }
748        else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
749            mv.visitCode();
750
751            Type[] argTypes = overridden.getArgumentTypes();
752            Type[] originalArgTypes = jvmSignature.getArgumentTypes();
753
754            InstructionAdapter iv = new InstructionAdapter(mv);
755            iv.load(0, OBJECT_TYPE);
756            for (int i = 0, reg = 1; i < argTypes.length; i++) {
757                StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
758                //noinspection AssignmentToForLoopParameter
759                reg += argTypes[i].getSize();
760            }
761
762            iv.invokevirtual(v.getThisName(), jvmSignature.getName(), jvmSignature.getDescriptor());
763
764            StackValue.onStack(jvmSignature.getReturnType()).put(overridden.getReturnType(), iv);
765
766            iv.areturn(overridden.getReturnType());
767            endVisit(mv, "bridge method", callableDescriptorToDeclaration(state.getBindingContext(), functionDescriptor));
768        }
769    }
770
771    public void genDelegate(FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) {
772        genDelegate(functionDescriptor, (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(), field,
773                    typeMapper.mapSignature(functionDescriptor),
774                    typeMapper.mapSignature(overriddenDescriptor.getOriginal())
775        );
776    }
777
778    public void genDelegate(
779            FunctionDescriptor functionDescriptor,
780            ClassDescriptor toClass,
781            StackValue field,
782            JvmMethodSignature jvmDelegateMethodSignature,
783            JvmMethodSignature jvmOverriddenMethodSignature
784    ) {
785        Method overriddenMethod = jvmOverriddenMethodSignature.getAsmMethod();
786        Method delegateMethod = jvmDelegateMethodSignature.getAsmMethod();
787
788        int flags = ACC_PUBLIC | ACC_SYNTHETIC; // TODO.
789
790        MethodVisitor mv = v.newMethod(null, flags, delegateMethod.getName(), delegateMethod.getDescriptor(), null, null);
791        if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
792            genStubCode(mv);
793        }
794        else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
795            mv.visitCode();
796
797            Type[] argTypes = delegateMethod.getArgumentTypes();
798            Type[] originalArgTypes = overriddenMethod.getArgumentTypes();
799
800            InstructionAdapter iv = new InstructionAdapter(mv);
801            iv.load(0, OBJECT_TYPE);
802            field.put(field.type, iv);
803            for (int i = 0, reg = 1; i < argTypes.length; i++) {
804                StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
805                //noinspection AssignmentToForLoopParameter
806                reg += argTypes[i].getSize();
807            }
808
809            String internalName = typeMapper.mapType(toClass).getInternalName();
810            if (toClass.getKind() == ClassKind.TRAIT) {
811                iv.invokeinterface(internalName, overriddenMethod.getName(), overriddenMethod.getDescriptor());
812            }
813            else {
814                iv.invokevirtual(internalName, overriddenMethod.getName(), overriddenMethod.getDescriptor());
815            }
816
817            StackValue.onStack(overriddenMethod.getReturnType()).put(delegateMethod.getReturnType(), iv);
818
819            iv.areturn(delegateMethod.getReturnType());
820            endVisit(mv, "Delegate method " + functionDescriptor + " to " + jvmOverriddenMethodSignature,
821                     descriptorToDeclaration(bindingContext, functionDescriptor.getContainingDeclaration()));
822
823            generateBridgeIfNeeded(owner, state, v, jvmDelegateMethodSignature.getAsmMethod(), functionDescriptor);
824        }
825    }
826}