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