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