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