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