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                Label methodEntry = new Label();
288                mv.visitLabel(methodEntry);
289                context.setMethodStartLabel(methodEntry);
290                labelsForSharedVars.putAll(createSharedVarsForParameters(mv, functionDescriptor, frameMap));
291    
292                if (!JetTypeMapper.isAccessor(functionDescriptor)) {
293                    genNotNullAssertionsForParameters(new InstructionAdapter(mv), state, functionDescriptor, frameMap);
294                }
295    
296                strategy.generateBody(mv, signature, context, getParentCodegen());
297    
298                localVariableNames.addAll(strategy.getLocalVariableNames());
299            }
300    
301            Label methodEnd = new Label();
302            mv.visitLabel(methodEnd);
303    
304    
305            Type thisType = getThisTypeForFunction(functionDescriptor, context);
306            generateLocalVariableTable(mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, localVariableNames, labelsForSharedVars, context.getContextKind());
307        }
308    
309        @NotNull
310        private static List<String> getParameterNamesAsStrings(@NotNull FunctionDescriptor functionDescriptor) {
311            List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters();
312            List<String> result = new ArrayList<String>(parameters.size());
313            for (ValueParameterDescriptor parameter : parameters) {
314                result.add(parameter.getName().asString());
315            }
316            return result;
317        }
318    
319        private void generateLocalVariableTable(
320                @NotNull MethodVisitor mv,
321                @NotNull JvmMethodSignature jvmMethodSignature,
322                @NotNull FunctionDescriptor functionDescriptor,
323                @Nullable Type thisType,
324                @NotNull Label methodBegin,
325                @NotNull Label methodEnd,
326                @NotNull Collection<String> localVariableNames,
327                @NotNull Map<Name, Label> labelsForSharedVars,
328                @NotNull OwnerKind ownerKind
329        ) {
330            Iterator<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters().iterator();
331            List<JvmMethodParameterSignature> params = jvmMethodSignature.getKotlinParameterTypes();
332            int shift = 0;
333    
334            boolean isStatic = AsmUtil.isStaticMethod(ownerKind, functionDescriptor);
335            if (!isStatic) {
336                //add this
337                if (thisType != null) {
338                    mv.visitLocalVariable("this", thisType.getDescriptor(), null, methodBegin, methodEnd, shift);
339                } else {
340                    //TODO: provide thisType for callable reference
341                }
342                shift++;
343            }
344    
345            for (int i = 0; i < params.size(); i++) {
346                JvmMethodParameterSignature param =  params.get(i);
347                JvmMethodParameterKind kind = param.getKind();
348                String parameterName = "$" + param.getKind().name().toLowerCase();
349    
350                if (needIndexForVar(kind)) {
351                    parameterName = parameterName + "$" + i;
352                }
353    
354                Type type = param.getAsmType();
355                if (kind == JvmMethodParameterKind.VALUE) {
356                    ValueParameterDescriptor parameter = valueParameters.next();
357                    Label divideLabel = labelsForSharedVars.get(parameter.getName());
358                    parameterName = parameter.getName().asString();
359                    if (divideLabel != null) {
360                        mv.visitLocalVariable(parameterName, type.getDescriptor(), null, methodBegin, divideLabel, shift);
361    
362                        String nameForSharedVar = createTmpVariableName(localVariableNames);
363                        localVariableNames.add(nameForSharedVar);
364    
365                        Type sharedVarType = typeMapper.getSharedVarType(parameter);
366                        mv.visitLocalVariable(nameForSharedVar, sharedVarType.getDescriptor(), null, divideLabel, methodEnd, shift);
367                        shift += Math.max(type.getSize(), sharedVarType.getSize());
368                        continue;
369                    }
370                }
371    
372                mv.visitLocalVariable(parameterName, type.getDescriptor(), null, methodBegin, methodEnd, shift);
373                shift += type.getSize();
374            }
375        }
376    
377        @NotNull
378        private Map<Name, Label> createSharedVarsForParameters(
379                @NotNull MethodVisitor mv,
380                @NotNull FunctionDescriptor functionDescriptor,
381                @NotNull FrameMap frameMap
382        ) {
383            Map<Name, Label> labelsForSharedVars = new HashMap<Name, Label>();
384    
385            for (ValueParameterDescriptor parameter : functionDescriptor.getValueParameters()) {
386                Type sharedVarType = typeMapper.getSharedVarType(parameter);
387                if (sharedVarType == null) {
388                    continue;
389                }
390    
391                Type localVarType = typeMapper.mapType(parameter);
392                int index = frameMap.getIndex(parameter);
393                mv.visitTypeInsn(NEW, sharedVarType.getInternalName());
394                mv.visitInsn(DUP);
395                mv.visitInsn(DUP);
396                mv.visitMethodInsn(INVOKESPECIAL, sharedVarType.getInternalName(), "<init>", "()V");
397                mv.visitVarInsn(localVarType.getOpcode(ILOAD), index);
398                mv.visitFieldInsn(PUTFIELD, sharedVarType.getInternalName(), "ref", StackValue.refType(localVarType).getDescriptor());
399    
400                Label labelForSharedVar = new Label();
401                mv.visitLabel(labelForSharedVar);
402    
403                labelsForSharedVars.put(parameter.getName(), labelForSharedVar);
404    
405                mv.visitVarInsn(sharedVarType.getOpcode(ISTORE), index);
406            }
407    
408            return labelsForSharedVars;
409        }
410    
411        private static void generateStaticDelegateMethodBody(
412                @NotNull MethodVisitor mv,
413                @NotNull Method asmMethod,
414                @NotNull NamespaceFacadeContext context
415        ) {
416            InstructionAdapter iv = new InstructionAdapter(mv);
417            Type[] argTypes = asmMethod.getArgumentTypes();
418    
419            // The first line of some namespace file is written to the line number attribute of a static delegate to allow to 'step into' it
420            // This is similar to what javac does with bridge methods
421            Label label = new Label();
422            iv.visitLabel(label);
423            iv.visitLineNumber(1, label);
424    
425            int k = 0;
426            for (Type argType : argTypes) {
427                iv.load(k, argType);
428                k += argType.getSize();
429            }
430            iv.invokestatic(context.getDelegateToClassType().getInternalName(), asmMethod.getName(), asmMethod.getDescriptor());
431            iv.areturn(asmMethod.getReturnType());
432        }
433    
434        private boolean needIndexForVar(JvmMethodParameterKind kind) {
435            return kind == JvmMethodParameterKind.SHARED_VAR || kind == JvmMethodParameterKind.SUPER_CALL_PARAM;
436        }
437    
438        public static void endVisit(MethodVisitor mv, @Nullable String description, @Nullable PsiElement method) {
439            try {
440                mv.visitMaxs(-1, -1);
441            }
442            catch (ProcessCanceledException e) {
443                throw e;
444            }
445            catch (Throwable t) {
446                String bytecode = renderByteCodeIfAvailable(mv);
447                throw new CompilationException(
448                        "wrong code generated" +
449                        (description != null ? " for " + description : "") +
450                        t.getClass().getName() +
451                        " " +
452                        t.getMessage() +
453                        (bytecode != null ? "\nbytecode:\n" + bytecode : ""),
454                        t, method);
455            }
456            mv.visitEnd();
457        }
458    
459        private static String renderByteCodeIfAvailable(MethodVisitor mv) {
460            String bytecode = null;
461            if (mv instanceof TraceMethodVisitor) {
462                TraceMethodVisitor traceMethodVisitor = (TraceMethodVisitor) mv;
463                StringWriter sw = new StringWriter();
464                PrintWriter pw = new PrintWriter(sw);
465                traceMethodVisitor.p.print(pw);
466                pw.close();
467                bytecode = sw.toString();
468            }
469            return bytecode;
470        }
471    
472        static void generateBridgeIfNeeded(
473                CodegenContext owner,
474                GenerationState state,
475                ClassBuilder v,
476                Method jvmSignature,
477                FunctionDescriptor functionDescriptor
478        ) {
479            if (owner.getContextKind() == OwnerKind.TRAIT_IMPL) {
480                return;
481            }
482    
483            Method method =
484                    state.getTypeMapper().mapSignature(functionDescriptor).getAsmMethod();
485    
486            Queue<FunctionDescriptor> bfsQueue = new LinkedList<FunctionDescriptor>();
487            Set<FunctionDescriptor> visited = new HashSet<FunctionDescriptor>();
488    
489            bfsQueue.offer(functionDescriptor.getOriginal());
490            visited.add(functionDescriptor.getOriginal());
491            for (FunctionDescriptor overriddenDescriptor : functionDescriptor.getOverriddenDescriptors()) {
492                FunctionDescriptor orig = overriddenDescriptor.getOriginal();
493                if (!visited.contains(orig)) {
494                    bfsQueue.offer(overriddenDescriptor);
495                    visited.add(overriddenDescriptor);
496                }
497            }
498    
499            Set<Method> bridgesToGenerate = new HashSet<Method>();
500            while (!bfsQueue.isEmpty()) {
501                FunctionDescriptor descriptor = bfsQueue.poll();
502                if (descriptor.getKind() == CallableMemberDescriptor.Kind.DECLARATION) {
503                    Method overridden =
504                            state.getTypeMapper().mapSignature(descriptor.getOriginal()).getAsmMethod();
505                    if (differentMethods(method, overridden)) {
506                        bridgesToGenerate.add(overridden);
507                    }
508                    continue;
509                }
510    
511                for (FunctionDescriptor overriddenDescriptor : descriptor.getOverriddenDescriptors()) {
512                    FunctionDescriptor orig = overriddenDescriptor.getOriginal();
513                    if (!visited.contains(orig)) {
514                        bfsQueue.offer(orig);
515                        visited.add(orig);
516                    }
517                }
518            }
519    
520            for (Method overridden : bridgesToGenerate) {
521                generateBridge(owner, state, v, jvmSignature, functionDescriptor, overridden);
522            }
523        }
524    
525        static void generateConstructorWithoutParametersIfNeeded(
526                @NotNull GenerationState state,
527                @NotNull CallableMethod method,
528                @NotNull ConstructorDescriptor constructorDescriptor,
529                @NotNull ClassBuilder classBuilder
530        ) {
531            if (!isDefaultConstructorNeeded(state.getBindingContext(), constructorDescriptor)) {
532                return;
533            }
534            int flags = getVisibilityAccessFlag(constructorDescriptor);
535            MethodVisitor mv = classBuilder.newMethod(null, flags, "<init>", "()V", null, null);
536    
537            if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) {
538                return;
539            }
540            else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
541                InstructionAdapter v = new InstructionAdapter(mv);
542                mv.visitCode();
543    
544                Type methodOwner = method.getOwner();
545                Method jvmSignature = method.getSignature().getAsmMethod();
546                v.load(0, methodOwner); // Load this on stack
547    
548                int mask = 0;
549                for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
550                    Type paramType = state.getTypeMapper().mapType(parameterDescriptor.getType());
551                    pushDefaultValueOnStack(paramType, v);
552                    mask |= (1 << parameterDescriptor.getIndex());
553                }
554                v.iconst(mask);
555                String desc = jvmSignature.getDescriptor().replace(")", "I)");
556                v.invokespecial(methodOwner.getInternalName(), "<init>", desc);
557                v.areturn(Type.VOID_TYPE);
558                endVisit(mv, "default constructor for " + methodOwner.getInternalName(), null);
559            }
560        }
561    
562        void generateDefaultIfNeeded(
563                @NotNull MethodContext owner,
564                @NotNull JvmMethodSignature signature,
565                @NotNull FunctionDescriptor functionDescriptor,
566                @NotNull OwnerKind kind,
567                @NotNull DefaultParameterValueLoader loadStrategy
568        ) {
569            DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration();
570    
571            if (kind != OwnerKind.TRAIT_IMPL &&
572                contextClass instanceof ClassDescriptor &&
573                ((ClassDescriptor) contextClass).getKind() == ClassKind.TRAIT) {
574                return;
575            }
576    
577            if (!isDefaultNeeded(functionDescriptor)) {
578                return;
579            }
580    
581            boolean isStatic = isStatic(kind);
582    
583            Method jvmSignature = signature.getAsmMethod();
584    
585            int flags = ACC_PUBLIC | ACC_SYNTHETIC; // TODO.
586    
587            Type ownerType;
588            if (contextClass instanceof NamespaceDescriptor) {
589                ownerType = state.getTypeMapper().getOwner(functionDescriptor, kind, true);
590            }
591            else if (contextClass instanceof ClassDescriptor) {
592                ownerType = state.getTypeMapper().mapClass((ClassDescriptor) contextClass);
593            }
594            else if (isLocalNamedFun(functionDescriptor)) {
595                ownerType = asmTypeForAnonymousClass(state.getBindingContext(), functionDescriptor);
596            }
597            else {
598                throw new IllegalStateException("Couldn't obtain owner name for " + functionDescriptor);
599            }
600    
601            String descriptor = jvmSignature.getDescriptor().replace(")", "I)");
602            boolean isConstructor = "<init>".equals(jvmSignature.getName());
603            if (!isStatic && !isConstructor) {
604                descriptor = descriptor.replace("(", "(" + ownerType.getDescriptor());
605            }
606            MethodVisitor mv = v.newMethod(null, flags | (isConstructor ? 0 : ACC_STATIC),
607                                           isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX,
608                                           descriptor, null, null);
609    
610            if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
611                generateDefaultImpl(owner, signature, functionDescriptor, isStatic, mv, loadStrategy);
612    
613            }
614        }
615    
616        private void generateDefaultImpl(
617                @NotNull MethodContext methodContext,
618                @NotNull JvmMethodSignature signature,
619                @NotNull FunctionDescriptor functionDescriptor,
620                boolean aStatic,
621                @NotNull MethodVisitor mv,
622                @NotNull DefaultParameterValueLoader loadStrategy
623        ) {
624            mv.visitCode();
625    
626            FrameMap frameMap = new FrameMap();
627    
628            if (!aStatic) {
629                frameMap.enterTemp(OBJECT_TYPE);
630            }
631    
632            Method jvmSignature = signature.getAsmMethod();
633            ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), methodContext, state, getParentCodegen());
634    
635            Type[] argTypes = jvmSignature.getArgumentTypes();
636            List<ValueParameterDescriptor> paramDescrs = functionDescriptor.getValueParameters();
637            Iterator<ValueParameterDescriptor> iterator = paramDescrs.iterator();
638    
639            int countOfExtraVarsInMethodArgs = 0;
640            List<JvmMethodParameterSignature> params = signature.getKotlinParameterTypes();
641    
642            for (int i = 0; i < params.size(); i++) {
643                JvmMethodParameterSignature parameterSignature = params.get(i);
644                if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) {
645                    countOfExtraVarsInMethodArgs++;
646                    frameMap.enterTemp(parameterSignature.getAsmType());
647                } else {
648                    frameMap.enter(iterator.next(), parameterSignature.getAsmType());
649                }
650            }
651    
652            int maskIndex = frameMap.enterTemp(Type.INT_TYPE);
653    
654            InstructionAdapter iv = new InstructionAdapter(mv);
655            loadExplicitArgumentsOnStack(iv, OBJECT_TYPE, aStatic, signature);
656    
657            for (int index = 0; index < paramDescrs.size(); index++) {
658                ValueParameterDescriptor parameterDescriptor = paramDescrs.get(index);
659    
660                Type t = argTypes[countOfExtraVarsInMethodArgs + index];
661    
662                if (parameterDescriptor.declaresDefaultValue()) {
663                    iv.load(maskIndex, Type.INT_TYPE);
664                    iv.iconst(1 << index);
665                    iv.and(Type.INT_TYPE);
666                    Label loadArg = new Label();
667                    iv.ifeq(loadArg);
668    
669                    loadStrategy.putValueOnStack(parameterDescriptor, codegen);
670    
671                    int ind = frameMap.getIndex(parameterDescriptor);
672                    iv.store(ind, t);
673    
674                    iv.mark(loadArg);
675                }
676    
677                iv.load(frameMap.getIndex(parameterDescriptor), t);
678            }
679    
680            CallableMethod method = null;
681            if (functionDescriptor instanceof ConstructorDescriptor) {
682                method = state.getTypeMapper().mapToCallableMethod((ConstructorDescriptor) functionDescriptor);
683            } else {
684                method = state.getTypeMapper()
685                        .mapToCallableMethod(functionDescriptor, false, isCallInsideSameClassAsDeclared(functionDescriptor, methodContext),
686                                             isCallInsideSameModuleAsDeclared(functionDescriptor, methodContext), OwnerKind.IMPLEMENTATION);
687            }
688    
689            iv.visitMethodInsn(method.getInvokeOpcode(), method.getOwner().getInternalName(), method.getSignature().getAsmMethod().getName(),
690                               method.getSignature().getAsmMethod().getDescriptor());
691    
692            iv.areturn(jvmSignature.getReturnType());
693    
694            endVisit(mv, "default method", callableDescriptorToDeclaration(state.getBindingContext(), functionDescriptor));
695        }
696    
697    
698        private static void loadExplicitArgumentsOnStack(
699                @NotNull InstructionAdapter iv,
700                @NotNull Type ownerType,
701                boolean isStatic,
702                @NotNull JvmMethodSignature signature
703        ) {
704            int var = 0;
705            if (!isStatic) {
706                iv.load(var, ownerType);
707                var += ownerType.getSize();
708            }
709    
710            List<JvmMethodParameterSignature> params = signature.getKotlinParameterTypes();
711            for (int i = 0; i < params.size(); i++) {
712                JvmMethodParameterSignature parameterSignature = params.get(i);
713                if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) {
714                    Type type = parameterSignature.getAsmType();
715                    iv.load(var, type);
716                    var += type.getSize();
717                }
718            }
719        }
720    
721        private static boolean isDefaultNeeded(FunctionDescriptor functionDescriptor) {
722            boolean needed = false;
723            if (functionDescriptor != null) {
724                for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) {
725                    if (parameterDescriptor.declaresDefaultValue()) {
726                        needed = true;
727                        break;
728                    }
729                }
730            }
731            return needed;
732        }
733    
734        private static boolean isDefaultConstructorNeeded(@NotNull BindingContext context, @NotNull ConstructorDescriptor constructorDescriptor) {
735            ClassDescriptor classDescriptor = constructorDescriptor.getContainingDeclaration();
736    
737            if (CodegenBinding.canHaveOuter(context, classDescriptor)) return false;
738    
739            if (classDescriptor.getVisibility() == Visibilities.PRIVATE ||
740                constructorDescriptor.getVisibility() == Visibilities.PRIVATE) return false;
741    
742            if (constructorDescriptor.getValueParameters().isEmpty()) return false;
743    
744            for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
745                if (!parameterDescriptor.declaresDefaultValue()) {
746                    return false;
747                }
748            }
749            return true;
750        }
751    
752        private static boolean differentMethods(Method method, Method overridden) {
753            if (!method.getReturnType().equals(overridden.getReturnType())) {
754                return true;
755            }
756            Type[] methodArgumentTypes = method.getArgumentTypes();
757            Type[] overriddenArgumentTypes = overridden.getArgumentTypes();
758            if (methodArgumentTypes.length != overriddenArgumentTypes.length) {
759                return true;
760            }
761            for (int i = 0; i != methodArgumentTypes.length; ++i) {
762                if (!methodArgumentTypes[i].equals(overriddenArgumentTypes[i])) {
763                    return true;
764                }
765            }
766            return false;
767        }
768    
769        private static void generateBridge(
770                CodegenContext owner,
771                GenerationState state,
772                ClassBuilder v,
773                Method jvmSignature,
774                FunctionDescriptor functionDescriptor,
775                Method overridden
776        ) {
777            int flags = ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC; // TODO.
778    
779            MethodVisitor mv = v.newMethod(null, flags, jvmSignature.getName(), overridden.getDescriptor(), null, null);
780            if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
781                mv.visitCode();
782    
783                Type[] argTypes = overridden.getArgumentTypes();
784                Type[] originalArgTypes = jvmSignature.getArgumentTypes();
785    
786                InstructionAdapter iv = new InstructionAdapter(mv);
787                iv.load(0, OBJECT_TYPE);
788                for (int i = 0, reg = 1; i < argTypes.length; i++) {
789                    StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
790                    //noinspection AssignmentToForLoopParameter
791                    reg += argTypes[i].getSize();
792                }
793    
794                iv.invokevirtual(v.getThisName(), jvmSignature.getName(), jvmSignature.getDescriptor());
795    
796                StackValue.onStack(jvmSignature.getReturnType()).put(overridden.getReturnType(), iv);
797    
798                iv.areturn(overridden.getReturnType());
799                endVisit(mv, "bridge method", callableDescriptorToDeclaration(state.getBindingContext(), functionDescriptor));
800            }
801        }
802    
803        public void genDelegate(FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) {
804            genDelegate(functionDescriptor, (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(), field,
805                        typeMapper.mapSignature(functionDescriptor),
806                        typeMapper.mapSignature(overriddenDescriptor.getOriginal())
807            );
808        }
809    
810        public void genDelegate(
811                FunctionDescriptor functionDescriptor,
812                ClassDescriptor toClass,
813                StackValue field,
814                JvmMethodSignature jvmDelegateMethodSignature,
815                JvmMethodSignature jvmOverriddenMethodSignature
816        ) {
817            Method overriddenMethod = jvmOverriddenMethodSignature.getAsmMethod();
818            Method delegateMethod = jvmDelegateMethodSignature.getAsmMethod();
819    
820            int flags = ACC_PUBLIC | ACC_SYNTHETIC; // TODO.
821    
822            MethodVisitor mv = v.newMethod(null, flags, delegateMethod.getName(), delegateMethod.getDescriptor(), null, null);
823            if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
824                mv.visitCode();
825    
826                Type[] argTypes = delegateMethod.getArgumentTypes();
827                Type[] originalArgTypes = overriddenMethod.getArgumentTypes();
828    
829                InstructionAdapter iv = new InstructionAdapter(mv);
830                iv.load(0, OBJECT_TYPE);
831                field.put(field.type, iv);
832                for (int i = 0, reg = 1; i < argTypes.length; i++) {
833                    StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
834                    //noinspection AssignmentToForLoopParameter
835                    reg += argTypes[i].getSize();
836                }
837    
838                String internalName = typeMapper.mapType(toClass).getInternalName();
839                if (toClass.getKind() == ClassKind.TRAIT) {
840                    iv.invokeinterface(internalName, overriddenMethod.getName(), overriddenMethod.getDescriptor());
841                }
842                else {
843                    iv.invokevirtual(internalName, overriddenMethod.getName(), overriddenMethod.getDescriptor());
844                }
845    
846                StackValue.onStack(overriddenMethod.getReturnType()).put(delegateMethod.getReturnType(), iv);
847    
848                iv.areturn(delegateMethod.getReturnType());
849                endVisit(mv, "Delegate method " + functionDescriptor + " to " + jvmOverriddenMethodSignature,
850                         descriptorToDeclaration(bindingContext, functionDescriptor.getContainingDeclaration()));
851    
852                generateBridgeIfNeeded(owner, state, v, jvmDelegateMethodSignature.getAsmMethod(), functionDescriptor);
853            }
854        }
855    }