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