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