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