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