001    /*
002     * Copyright 2010-2013 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.jet.codegen.state;
018    
019    import com.intellij.openapi.util.text.StringUtil;
020    import com.intellij.psi.PsiElement;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.jet.codegen.*;
024    import org.jetbrains.jet.codegen.binding.CalculatedClosure;
025    import org.jetbrains.jet.codegen.binding.CodegenBinding;
026    import org.jetbrains.jet.codegen.binding.PsiCodegenPredictor;
027    import org.jetbrains.jet.codegen.context.CodegenContext;
028    import org.jetbrains.jet.codegen.signature.BothSignatureWriter;
029    import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedCallableMemberDescriptor;
030    import org.jetbrains.jet.lang.descriptors.*;
031    import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
032    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
033    import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor;
034    import org.jetbrains.jet.lang.psi.JetFile;
035    import org.jetbrains.jet.lang.resolve.*;
036    import org.jetbrains.jet.lang.resolve.annotations.AnnotationsPackage;
037    import org.jetbrains.jet.lang.resolve.calls.model.DefaultValueArgument;
038    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
039    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
040    import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
041    import org.jetbrains.jet.lang.resolve.constants.StringValue;
042    import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
043    import org.jetbrains.jet.lang.resolve.java.JvmAbi;
044    import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
045    import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodParameterKind;
046    import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodParameterSignature;
047    import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodSignature;
048    import org.jetbrains.jet.lang.resolve.java.mapping.KotlinToJavaTypesMap;
049    import org.jetbrains.jet.lang.resolve.kotlin.PackagePartClassUtils;
050    import org.jetbrains.jet.lang.resolve.name.FqName;
051    import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
052    import org.jetbrains.jet.lang.resolve.name.SpecialNames;
053    import org.jetbrains.jet.lang.types.*;
054    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
055    import org.jetbrains.org.objectweb.asm.Type;
056    import org.jetbrains.org.objectweb.asm.commons.Method;
057    
058    import java.io.File;
059    import java.util.ArrayList;
060    import java.util.List;
061    import java.util.Map;
062    
063    import static org.jetbrains.jet.codegen.AsmUtil.boxType;
064    import static org.jetbrains.jet.codegen.AsmUtil.isStaticMethod;
065    import static org.jetbrains.jet.codegen.JvmCodegenUtil.*;
066    import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
067    import static org.jetbrains.jet.lang.resolve.BindingContextUtils.isVarCapturedInClosure;
068    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
069    import static org.jetbrains.org.objectweb.asm.Opcodes.*;
070    
071    public class JetTypeMapper {
072        private final BindingContext bindingContext;
073        private final ClassBuilderMode classBuilderMode;
074    
075        public JetTypeMapper(@NotNull BindingContext bindingContext, @NotNull ClassBuilderMode classBuilderMode) {
076            this.bindingContext = bindingContext;
077            this.classBuilderMode = classBuilderMode;
078        }
079    
080        @NotNull
081        public BindingContext getBindingContext() {
082            return bindingContext;
083        }
084    
085        private enum JetTypeMapperMode {
086            /**
087             * foo.Bar is mapped to Lfoo/Bar;
088             */
089            IMPL,
090            /**
091             * kotlin.Int is mapped to I
092             */
093            VALUE,
094            /**
095             * kotlin.Int is mapped to Ljava/lang/Integer;
096             */
097            TYPE_PARAMETER,
098            /**
099             * kotlin.Int is mapped to Ljava/lang/Integer;
100             * No projections allowed in immediate arguments
101             */
102            SUPER_TYPE
103        }
104    
105        @NotNull
106        public Type mapOwner(@NotNull DeclarationDescriptor descriptor, boolean isInsideModule) {
107            if (isLocalNamedFun(descriptor)) {
108                return asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor);
109            }
110    
111            DeclarationDescriptor container = descriptor.getContainingDeclaration();
112            if (container instanceof PackageFragmentDescriptor) {
113                return Type.getObjectType(internalNameForPackage(
114                        (PackageFragmentDescriptor) container,
115                        (CallableMemberDescriptor) descriptor,
116                        isInsideModule
117                ));
118            }
119            else if (container instanceof ClassDescriptor) {
120                return mapClass((ClassDescriptor) container);
121            }
122            else if (container instanceof ScriptDescriptor) {
123                return asmTypeForScriptDescriptor(bindingContext, (ScriptDescriptor) container);
124            }
125            else {
126                throw new UnsupportedOperationException("Don't know how to map owner for " + descriptor);
127            }
128        }
129    
130        @NotNull
131        private static String internalNameForPackage(
132                @NotNull PackageFragmentDescriptor packageFragment,
133                @NotNull CallableMemberDescriptor descriptor,
134                boolean insideModule
135        ) {
136            if (insideModule) {
137                JetFile file = DescriptorToSourceUtils.getContainingFile(descriptor);
138                if (file != null) {
139                    return PackagePartClassUtils.getPackagePartInternalName(file);
140                }
141    
142                CallableMemberDescriptor directMember = getDirectMember(descriptor);
143    
144                if (directMember instanceof DeserializedCallableMemberDescriptor) {
145                    FqName packagePartFqName = PackagePartClassUtils.getPackagePartFqName((DeserializedCallableMemberDescriptor) directMember);
146                    return AsmUtil.internalNameByFqNameWithoutInnerClasses(packagePartFqName);
147                }
148            }
149    
150            return PackageClassUtils.getPackageClassInternalName(packageFragment.getFqName());
151        }
152    
153        @NotNull
154        public Type mapReturnType(@NotNull CallableDescriptor descriptor) {
155            return mapReturnType(descriptor, null);
156        }
157    
158        @NotNull
159        private Type mapReturnType(@NotNull CallableDescriptor descriptor, @Nullable BothSignatureWriter sw) {
160            JetType returnType = descriptor.getReturnType();
161            assert returnType != null : "Function has no return type: " + descriptor;
162            if (returnType.equals(KotlinBuiltIns.getInstance().getUnitType())
163                && !TypeUtils.isNullableType(returnType)
164                && !(descriptor instanceof PropertyGetterDescriptor)) {
165                if (sw != null) {
166                    sw.writeAsmType(Type.VOID_TYPE);
167                }
168                return Type.VOID_TYPE;
169            }
170            else {
171                return mapType(returnType, sw, JetTypeMapperMode.VALUE, Variance.OUT_VARIANCE, false);
172            }
173        }
174    
175        @NotNull
176        private Type mapType(@NotNull JetType jetType, @NotNull JetTypeMapperMode mode) {
177            return mapType(jetType, null, mode);
178        }
179    
180        @NotNull
181        public Type mapSupertype(@NotNull JetType jetType, @Nullable BothSignatureWriter signatureVisitor) {
182            return mapType(jetType, signatureVisitor, JetTypeMapperMode.SUPER_TYPE);
183        }
184    
185        @NotNull
186        public Type mapClass(@NotNull ClassifierDescriptor classifier) {
187            return mapType(classifier.getDefaultType(), null, JetTypeMapperMode.IMPL);
188        }
189    
190        @NotNull
191        public Type mapType(@NotNull JetType jetType) {
192            return mapType(jetType, null, JetTypeMapperMode.VALUE);
193        }
194    
195        @NotNull
196        public Type mapType(@NotNull CallableDescriptor descriptor) {
197            //noinspection ConstantConditions
198            return mapType(descriptor.getReturnType());
199        }
200    
201        @NotNull
202        public Type mapType(@NotNull ClassifierDescriptor descriptor) {
203            return mapType(descriptor.getDefaultType());
204        }
205    
206        @NotNull
207        private Type mapType(@NotNull JetType jetType, @Nullable BothSignatureWriter signatureVisitor, @NotNull JetTypeMapperMode mode) {
208            return mapType(jetType, signatureVisitor, mode, Variance.INVARIANT, false);
209        }
210    
211        @NotNull
212        private Type mapType(
213                @NotNull JetType jetType,
214                @Nullable BothSignatureWriter signatureVisitor,
215                @NotNull JetTypeMapperMode kind,
216                @NotNull Variance howThisTypeIsUsed,
217                boolean arrayParameter
218        ) {
219            Type known = null;
220            DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
221    
222            if (descriptor instanceof ClassDescriptor) {
223                FqNameUnsafe className = DescriptorUtils.getFqName(descriptor);
224                if (className.isSafe()) {
225                    known = KotlinToJavaTypesMap.getInstance().getJavaAnalog(className.toSafe(), TypeUtils.isNullableType(jetType));
226                }
227            }
228    
229            boolean projectionsAllowed = kind != JetTypeMapperMode.SUPER_TYPE;
230            if (known != null) {
231                if (kind == JetTypeMapperMode.VALUE) {
232                    return mapKnownAsmType(jetType, known, signatureVisitor, howThisTypeIsUsed);
233                }
234                else if (kind == JetTypeMapperMode.TYPE_PARAMETER || kind == JetTypeMapperMode.SUPER_TYPE) {
235                    return mapKnownAsmType(jetType, boxType(known), signatureVisitor, howThisTypeIsUsed, arrayParameter, projectionsAllowed);
236                }
237                else if (kind == JetTypeMapperMode.IMPL) {
238                    // TODO: enable and fix tests
239                    //throw new IllegalStateException("must not map known type to IMPL when not compiling builtins: " + jetType);
240                    return mapKnownAsmType(jetType, known, signatureVisitor, howThisTypeIsUsed);
241                }
242                else {
243                    throw new IllegalStateException("unknown kind: " + kind);
244                }
245            }
246    
247            TypeConstructor constructor = jetType.getConstructor();
248            if (constructor instanceof IntersectionTypeConstructor) {
249                jetType = CommonSupertypes.commonSupertype(new ArrayList<JetType>(constructor.getSupertypes()));
250            }
251    
252            if (descriptor == null) {
253                throw new UnsupportedOperationException("no descriptor for type constructor of " + jetType);
254            }
255    
256            if (ErrorUtils.isError(descriptor)) {
257                if (classBuilderMode != ClassBuilderMode.LIGHT_CLASSES) {
258                    throw new IllegalStateException(generateErrorMessageForErrorType(jetType, descriptor));
259                }
260                Type asmType = Type.getObjectType("error/NonExistentClass");
261                if (signatureVisitor != null) {
262                    signatureVisitor.writeAsmType(asmType);
263                }
264                return asmType;
265            }
266    
267            if (descriptor instanceof ClassDescriptor && KotlinBuiltIns.getInstance().isArray(jetType)) {
268                if (jetType.getArguments().size() != 1) {
269                    throw new UnsupportedOperationException("arrays must have one type argument");
270                }
271                TypeProjection memberProjection = jetType.getArguments().get(0);
272                JetType memberType = memberProjection.getType();
273    
274                if (signatureVisitor != null) {
275                    signatureVisitor.writeArrayType();
276                    mapType(memberType, signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER, memberProjection.getProjectionKind(), true);
277                    signatureVisitor.writeArrayEnd();
278                }
279    
280                return Type.getType("[" + boxType(mapType(memberType, kind)).getDescriptor());
281            }
282    
283            if (descriptor instanceof ClassDescriptor) {
284                Type asmType = computeAsmType((ClassDescriptor) descriptor.getOriginal());
285                writeGenericType(signatureVisitor, asmType, jetType, howThisTypeIsUsed, projectionsAllowed);
286                return asmType;
287            }
288    
289            if (descriptor instanceof TypeParameterDescriptor) {
290                TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) descriptor;
291                Type type = mapType(typeParameterDescriptor.getUpperBounds().iterator().next(), kind);
292                if (signatureVisitor != null) {
293                    signatureVisitor.writeTypeVariable(typeParameterDescriptor.getName(), type);
294                }
295                return type;
296            }
297    
298            throw new UnsupportedOperationException("Unknown type " + jetType);
299        }
300    
301        @NotNull
302        private Type computeAsmType(@NotNull ClassDescriptor klass) {
303            Type alreadyComputedType = bindingContext.get(ASM_TYPE, klass);
304            if (alreadyComputedType != null) {
305                return alreadyComputedType;
306            }
307    
308            Type asmType = Type.getObjectType(computeAsmTypeImpl(klass));
309            assert PsiCodegenPredictor.checkPredictedNameFromPsi(klass, asmType);
310            return asmType;
311        }
312    
313        @NotNull
314        private String computeAsmTypeImpl(@NotNull ClassDescriptor klass) {
315            DeclarationDescriptor container = klass.getContainingDeclaration();
316    
317            String name = SpecialNames.safeIdentifier(klass.getName()).getIdentifier();
318            if (container instanceof PackageFragmentDescriptor) {
319                FqName fqName = ((PackageFragmentDescriptor) container).getFqName();
320                return fqName.isRoot() ? name : fqName.asString().replace('.', '/') + '/' + name;
321            }
322    
323            if (container instanceof ScriptDescriptor) {
324                return asmTypeForScriptDescriptor(bindingContext, (ScriptDescriptor) container).getInternalName() + "$" + name;
325            }
326    
327            assert container instanceof ClassDescriptor : "Unexpected container: " + container + " for " + klass;
328    
329            String containerInternalName = computeAsmTypeImpl((ClassDescriptor) container);
330            switch (klass.getKind()) {
331                case ENUM_ENTRY:
332                    return containerInternalName;
333                case CLASS_OBJECT:
334                    return containerInternalName + JvmAbi.CLASS_OBJECT_SUFFIX;
335                default:
336                    return containerInternalName + "$" + name;
337            }
338        }
339    
340        @NotNull
341        public Type mapTraitImpl(@NotNull ClassDescriptor descriptor) {
342            return Type.getObjectType(mapType(descriptor).getInternalName() + JvmAbi.TRAIT_IMPL_SUFFIX);
343        }
344    
345        @NotNull
346        private String generateErrorMessageForErrorType(@NotNull JetType type, @NotNull DeclarationDescriptor descriptor) {
347            PsiElement declarationElement = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
348            PsiElement parentDeclarationElement = null;
349            if (declarationElement != null) {
350                DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
351                if (containingDeclaration != null) {
352                    parentDeclarationElement = DescriptorToSourceUtils.descriptorToDeclaration(containingDeclaration);
353                }
354            }
355    
356            return String.format("Error types are not allowed when classBuilderMode = %s. " +
357                                 "Type: %s (%s). Descriptor: %s. For declaration %s:%s in %s:%s",
358                                 classBuilderMode,
359                                 type,
360                                 type.getClass().getSimpleName(),
361                                 descriptor,
362                                 declarationElement,
363                                 declarationElement != null ? declarationElement.getText() : "null",
364                                 parentDeclarationElement,
365                                 parentDeclarationElement != null ? parentDeclarationElement.getText() : "null");
366        }
367    
368        private void writeGenericType(
369                BothSignatureWriter signatureVisitor,
370                Type asmType,
371                JetType jetType,
372                Variance howThisTypeIsUsed,
373                boolean projectionsAllowed
374        ) {
375            if (signatureVisitor != null) {
376                signatureVisitor.writeClassBegin(asmType);
377    
378                List<TypeProjection> arguments = jetType.getArguments();
379                for (TypeParameterDescriptor parameter : jetType.getConstructor().getParameters()) {
380                    TypeProjection argument = arguments.get(parameter.getIndex());
381    
382                    Variance projectionKind = projectionsAllowed
383                                              ? getEffectiveVariance(
384                                                        parameter.getVariance(),
385                                                        argument.getProjectionKind(),
386                                                        howThisTypeIsUsed
387                                                )
388                                              : Variance.INVARIANT;
389                    signatureVisitor.writeTypeArgument(projectionKind);
390    
391                    mapType(argument.getType(), signatureVisitor, JetTypeMapperMode.TYPE_PARAMETER);
392                    signatureVisitor.writeTypeArgumentEnd();
393                }
394                signatureVisitor.writeClassEnd();
395            }
396        }
397    
398        private static Variance getEffectiveVariance(Variance parameterVariance, Variance projectionKind, Variance howThisTypeIsUsed) {
399            // Return type must not contain wildcards
400            if (howThisTypeIsUsed == Variance.OUT_VARIANCE) return projectionKind;
401    
402            if (parameterVariance == Variance.INVARIANT) {
403                return projectionKind;
404            }
405            if (projectionKind == Variance.INVARIANT) {
406                return parameterVariance;
407            }
408            if (parameterVariance == projectionKind) {
409                return parameterVariance;
410            }
411    
412            // In<out X> = In<*>
413            // Out<in X> = Out<*>
414            return Variance.OUT_VARIANCE;
415        }
416    
417        private Type mapKnownAsmType(
418                JetType jetType,
419                Type asmType,
420                @Nullable BothSignatureWriter signatureVisitor,
421                @NotNull Variance howThisTypeIsUsed
422        ) {
423            return mapKnownAsmType(jetType, asmType, signatureVisitor, howThisTypeIsUsed, false, true);
424        }
425    
426        private Type mapKnownAsmType(
427                JetType jetType,
428                Type asmType,
429                @Nullable BothSignatureWriter signatureVisitor,
430                @NotNull Variance howThisTypeIsUsed,
431                boolean arrayParameter,
432                boolean allowProjections
433        ) {
434            if (signatureVisitor != null) {
435                if (jetType.getArguments().isEmpty()) {
436                    if (arrayParameter && howThisTypeIsUsed == Variance.IN_VARIANCE) {
437                        asmType = AsmTypeConstants.OBJECT_TYPE;
438                    }
439                    signatureVisitor.writeAsmType(asmType);
440                }
441                else {
442                    writeGenericType(signatureVisitor, asmType, jetType, howThisTypeIsUsed, allowProjections);
443                }
444            }
445            return asmType;
446        }
447    
448        @NotNull
449        public CallableMethod mapToCallableMethod(
450                @NotNull FunctionDescriptor descriptor,
451                boolean superCall,
452                @NotNull CodegenContext<?> context
453        ) {
454            DeclarationDescriptor functionParent = descriptor.getOriginal().getContainingDeclaration();
455    
456            FunctionDescriptor functionDescriptor = unwrapFakeOverride(descriptor.getOriginal());
457    
458            JvmMethodSignature signature;
459            Type owner;
460            Type ownerForDefaultImpl;
461            Type ownerForDefaultParam;
462            int invokeOpcode;
463            Type thisClass;
464    
465            if (functionParent instanceof ClassDescriptor) {
466                FunctionDescriptor declarationFunctionDescriptor = findAnyDeclaration(functionDescriptor);
467    
468                ClassDescriptor currentOwner = (ClassDescriptor) functionParent;
469                ClassDescriptor declarationOwner = (ClassDescriptor) declarationFunctionDescriptor.getContainingDeclaration();
470    
471                boolean originalIsInterface = isInterface(declarationOwner);
472                boolean currentIsInterface = isInterface(currentOwner);
473    
474                boolean isInterface = currentIsInterface && originalIsInterface;
475    
476                ClassDescriptor ownerForDefault = (ClassDescriptor) findBaseDeclaration(functionDescriptor).getContainingDeclaration();
477                ownerForDefaultParam = mapClass(ownerForDefault);
478                ownerForDefaultImpl = isInterface(ownerForDefault) ? mapTraitImpl(ownerForDefault) : ownerForDefaultParam;
479    
480                if (isInterface && superCall) {
481                    invokeOpcode = INVOKESTATIC;
482                    signature = mapSignature(functionDescriptor, OwnerKind.TRAIT_IMPL);
483                    owner = mapTraitImpl(currentOwner);
484                    thisClass = mapClass(currentOwner);
485                }
486                else {
487                    if (isStaticDeclaration(functionDescriptor) ||
488                        isAccessor(functionDescriptor) ||
489                        AnnotationsPackage.isPlatformStaticInObject(functionDescriptor)) {
490                        invokeOpcode = INVOKESTATIC;
491                    }
492                    else if (isInterface) {
493                        invokeOpcode = INVOKEINTERFACE;
494                    }
495                    else {
496                        boolean isPrivateFunInvocation = functionDescriptor.getVisibility() == Visibilities.PRIVATE;
497                        invokeOpcode = superCall || isPrivateFunInvocation ? INVOKESPECIAL : INVOKEVIRTUAL;
498                    }
499    
500                    signature = mapSignature(functionDescriptor.getOriginal());
501    
502                    ClassDescriptor receiver = currentIsInterface && !originalIsInterface ? declarationOwner : currentOwner;
503                    owner = mapClass(receiver);
504                    thisClass = owner;
505                }
506            }
507            else {
508                signature = mapSignature(functionDescriptor.getOriginal());
509                owner = mapOwner(functionDescriptor, isCallInsideSameModuleAsDeclared(functionDescriptor, context, getOutDirectory()));
510                ownerForDefaultParam = owner;
511                ownerForDefaultImpl = owner;
512                if (functionParent instanceof PackageFragmentDescriptor) {
513                    invokeOpcode = INVOKESTATIC;
514                    thisClass = null;
515                }
516                else if (functionDescriptor instanceof ConstructorDescriptor) {
517                    invokeOpcode = INVOKESPECIAL;
518                    thisClass = null;
519                }
520                else {
521                    invokeOpcode = INVOKEVIRTUAL;
522                    thisClass = owner;
523                }
524            }
525    
526            Type calleeType = isLocalNamedFun(functionDescriptor) ? owner : null;
527    
528            Type receiverParameterType;
529            ReceiverParameterDescriptor receiverParameter = functionDescriptor.getOriginal().getExtensionReceiverParameter();
530            if (receiverParameter != null) {
531                receiverParameterType = mapType(receiverParameter.getType());
532            }
533            else {
534                receiverParameterType = null;
535            }
536            return new CallableMethod(
537                    owner, ownerForDefaultImpl, ownerForDefaultParam, signature, invokeOpcode,
538                    thisClass, receiverParameterType, calleeType);
539        }
540    
541        public static boolean isAccessor(@NotNull CallableMemberDescriptor descriptor) {
542            return descriptor instanceof AccessorForCallableDescriptor<?>;
543        }
544    
545        @NotNull
546        private static FunctionDescriptor findAnyDeclaration(@NotNull FunctionDescriptor function) {
547            if (function.getKind() == CallableMemberDescriptor.Kind.DECLARATION) {
548                return function;
549            }
550            return findBaseDeclaration(function);
551        }
552    
553        @NotNull
554        private static FunctionDescriptor findBaseDeclaration(@NotNull FunctionDescriptor function) {
555            if (function.getOverriddenDescriptors().isEmpty()) {
556                return function;
557            }
558            else {
559                // TODO: prefer class to interface
560                return findBaseDeclaration(function.getOverriddenDescriptors().iterator().next());
561            }
562        }
563    
564        @NotNull
565        private static String mapFunctionName(@NotNull FunctionDescriptor descriptor) {
566            String platformName = getPlatformName(descriptor);
567            if (platformName != null) return platformName;
568    
569            if (descriptor instanceof PropertyAccessorDescriptor) {
570                PropertyDescriptor property = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty();
571                if (isAnnotationClass(property.getContainingDeclaration())) {
572                    return property.getName().asString();
573                }
574    
575                if (descriptor instanceof PropertyGetterDescriptor) {
576                    return PropertyCodegen.getterName(property.getName());
577                }
578                else {
579                    return PropertyCodegen.setterName(property.getName());
580                }
581            }
582            else if (isLocalNamedFun(descriptor) || descriptor instanceof AnonymousFunctionDescriptor) {
583                return "invoke";
584            }
585            else {
586                return descriptor.getName().asString();
587            }
588        }
589    
590        @Nullable
591        private static String getPlatformName(@NotNull Annotated descriptor) {
592            AnnotationDescriptor platformNameAnnotation = descriptor.getAnnotations().findAnnotation(new FqName("kotlin.platform.platformName"));
593            if (platformNameAnnotation == null) return null;
594    
595            Map<ValueParameterDescriptor, CompileTimeConstant<?>> arguments = platformNameAnnotation.getAllValueArguments();
596            if (arguments.isEmpty()) return null;
597    
598            CompileTimeConstant<?> name = arguments.values().iterator().next();
599            if (!(name instanceof StringValue)) return null;
600    
601            return ((StringValue) name).getValue();
602        }
603    
604        @NotNull
605        public JvmMethodSignature mapSignature(@NotNull FunctionDescriptor descriptor) {
606            return mapSignature(descriptor, OwnerKind.IMPLEMENTATION);
607        }
608    
609        @NotNull
610        public JvmMethodSignature mapSignature(@NotNull FunctionDescriptor f, @NotNull OwnerKind kind) {
611            BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD);
612    
613            if (f instanceof ConstructorDescriptor) {
614                sw.writeParametersStart();
615                writeAdditionalConstructorParameters((ConstructorDescriptor) f, sw);
616    
617                for (ValueParameterDescriptor parameter : f.getOriginal().getValueParameters()) {
618                    writeParameter(sw, parameter.getType());
619                }
620    
621                writeVoidReturn(sw);
622            }
623            else {
624                writeFormalTypeParameters(getDirectMember(f).getTypeParameters(), sw);
625    
626                sw.writeParametersStart();
627                writeThisIfNeeded(f, kind, sw);
628    
629                ReceiverParameterDescriptor receiverParameter = f.getExtensionReceiverParameter();
630                if (receiverParameter != null) {
631                    writeParameter(sw, JvmMethodParameterKind.RECEIVER, receiverParameter.getType());
632                }
633    
634                for (ValueParameterDescriptor parameter : f.getValueParameters()) {
635                    writeParameter(sw, parameter.getType());
636                }
637    
638                sw.writeReturnType();
639                if (forceBoxedReturnType(f)) {
640                    // TYPE_PARAMETER is a hack to automatically box the return type
641                    //noinspection ConstantConditions
642                    mapType(f.getReturnType(), sw, JetTypeMapperMode.TYPE_PARAMETER);
643                }
644                else {
645                    mapReturnType(f, sw);
646                }
647                sw.writeReturnTypeEnd();
648            }
649    
650            return sw.makeJvmMethodSignature(mapFunctionName(f));
651        }
652    
653        @NotNull
654        public static String getDefaultDescriptor(@NotNull Method method, boolean isExtension) {
655            String descriptor = method.getDescriptor();
656            int argumentsCount = (Type.getArgumentsAndReturnSizes(descriptor) >> 2) - 1;
657            if (isExtension) {
658                argumentsCount--;
659            }
660            int maskArgumentsCount = (argumentsCount + Integer.SIZE - 1) / Integer.SIZE;
661            String maskArguments = StringUtil.repeat(Type.INT_TYPE.getDescriptor(), maskArgumentsCount);
662            return descriptor.replace(")", maskArguments + ")");
663        }
664    
665        @NotNull
666        public Method mapDefaultMethod(@NotNull FunctionDescriptor functionDescriptor, @NotNull OwnerKind kind, @NotNull CodegenContext<?> context) {
667            Method jvmSignature = mapSignature(functionDescriptor, kind).getAsmMethod();
668            Type ownerType = mapOwner(functionDescriptor, isCallInsideSameModuleAsDeclared(functionDescriptor, context, getOutDirectory()));
669            String descriptor = getDefaultDescriptor(jvmSignature, functionDescriptor.getExtensionReceiverParameter() != null);
670            boolean isConstructor = "<init>".equals(jvmSignature.getName());
671            if (!isStaticMethod(kind, functionDescriptor) && !isConstructor) {
672                descriptor = descriptor.replace("(", "(" + ownerType.getDescriptor());
673            }
674    
675            return new Method(isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, descriptor);
676        }
677    
678        /**
679         * @return true iff a given function descriptor should be compiled to a method with boxed return type regardless of whether return type
680         * of that descriptor is nullable or not. This happens when a function returning a value of a primitive type overrides another function
681         * with a non-primitive return type. In that case the generated method's return type should be boxed: otherwise it's not possible to use
682         * this class from Java since javac issues errors when loading the class (incompatible return types)
683         */
684        private static boolean forceBoxedReturnType(@NotNull FunctionDescriptor descriptor) {
685            //noinspection ConstantConditions
686            if (!KotlinBuiltIns.getInstance().isPrimitiveType(descriptor.getReturnType())) return false;
687    
688            for (FunctionDescriptor overridden : getAllOverriddenDescriptors(descriptor)) {
689                //noinspection ConstantConditions
690                if (!KotlinBuiltIns.getInstance().isPrimitiveType(overridden.getOriginal().getReturnType())) return true;
691            }
692    
693            return false;
694        }
695    
696        private static void writeVoidReturn(@NotNull BothSignatureWriter sw) {
697            sw.writeReturnType();
698            sw.writeAsmType(Type.VOID_TYPE);
699            sw.writeReturnTypeEnd();
700        }
701    
702        @Nullable
703        public String mapFieldSignature(@NotNull JetType backingFieldType) {
704            BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.TYPE);
705            mapType(backingFieldType, sw, JetTypeMapperMode.VALUE);
706            return sw.makeJavaGenericSignature();
707        }
708    
709        private void writeThisIfNeeded(
710                @NotNull CallableMemberDescriptor descriptor,
711                @NotNull OwnerKind kind,
712                @NotNull BothSignatureWriter sw
713        ) {
714            ClassDescriptor thisType;
715            if (kind == OwnerKind.TRAIT_IMPL) {
716                thisType = getTraitImplThisParameterClass((ClassDescriptor) descriptor.getContainingDeclaration());
717            }
718            else if (isAccessor(descriptor) && descriptor.getDispatchReceiverParameter() != null) {
719                thisType = (ClassDescriptor) descriptor.getContainingDeclaration();
720            }
721            else return;
722    
723            writeParameter(sw, JvmMethodParameterKind.THIS, thisType.getDefaultType());
724        }
725    
726        @NotNull
727        private static ClassDescriptor getTraitImplThisParameterClass(@NotNull ClassDescriptor traitDescriptor) {
728            for (ClassDescriptor descriptor : DescriptorUtils.getSuperclassDescriptors(traitDescriptor)) {
729                if (descriptor.getKind() != ClassKind.TRAIT) {
730                    return descriptor;
731                }
732            }
733            return traitDescriptor;
734        }
735    
736        public void writeFormalTypeParameters(@NotNull List<TypeParameterDescriptor> typeParameters, @NotNull BothSignatureWriter sw) {
737            for (TypeParameterDescriptor typeParameter : typeParameters) {
738                writeFormalTypeParameter(typeParameter, sw);
739            }
740        }
741    
742        private void writeFormalTypeParameter(@NotNull TypeParameterDescriptor typeParameterDescriptor, @NotNull BothSignatureWriter sw) {
743            if (classBuilderMode == ClassBuilderMode.LIGHT_CLASSES && typeParameterDescriptor.getName().isSpecial()) {
744                // If a type parameter has no name, the code below fails, but it should recover in case of light classes
745                return;
746            }
747    
748            sw.writeFormalTypeParameter(typeParameterDescriptor.getName().asString());
749    
750            classBound:
751            {
752                sw.writeClassBound();
753    
754                for (JetType jetType : typeParameterDescriptor.getUpperBounds()) {
755                    if (jetType.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
756                        if (!isInterface(jetType)) {
757                            mapType(jetType, sw, JetTypeMapperMode.TYPE_PARAMETER);
758                            break classBound;
759                        }
760                    }
761                }
762    
763                // "extends Object" is optional according to ClassFileFormat-Java5.pdf
764                // but javac complaints to signature:
765                // <P:>Ljava/lang/Object;
766                // TODO: avoid writing java/lang/Object if interface list is not empty
767            }
768            sw.writeClassBoundEnd();
769    
770            for (JetType jetType : typeParameterDescriptor.getUpperBounds()) {
771                ClassifierDescriptor classifier = jetType.getConstructor().getDeclarationDescriptor();
772                if (classifier instanceof ClassDescriptor) {
773                    if (isInterface(jetType)) {
774                        sw.writeInterfaceBound();
775                        mapType(jetType, sw, JetTypeMapperMode.TYPE_PARAMETER);
776                        sw.writeInterfaceBoundEnd();
777                    }
778                }
779                else if (classifier instanceof TypeParameterDescriptor) {
780                    sw.writeInterfaceBound();
781                    mapType(jetType, sw, JetTypeMapperMode.TYPE_PARAMETER);
782                    sw.writeInterfaceBoundEnd();
783                }
784                else {
785                    throw new UnsupportedOperationException("Unknown classifier: " + classifier);
786                }
787            }
788        }
789    
790        private void writeParameter(@NotNull BothSignatureWriter sw, @NotNull JetType type) {
791            writeParameter(sw, JvmMethodParameterKind.VALUE, type);
792        }
793    
794        private void writeParameter(@NotNull BothSignatureWriter sw, @NotNull JvmMethodParameterKind kind, @NotNull JetType type) {
795            sw.writeParameterType(kind);
796            mapType(type, sw, JetTypeMapperMode.VALUE);
797            sw.writeParameterTypeEnd();
798        }
799    
800        private static void writeParameter(@NotNull BothSignatureWriter sw, @NotNull JvmMethodParameterKind kind, @NotNull Type type) {
801            sw.writeParameterType(kind);
802            sw.writeAsmType(type);
803            sw.writeParameterTypeEnd();
804        }
805    
806        private void writeAdditionalConstructorParameters(@NotNull ConstructorDescriptor descriptor, @NotNull BothSignatureWriter sw) {
807            CalculatedClosure closure = bindingContext.get(CodegenBinding.CLOSURE, descriptor.getContainingDeclaration());
808    
809            ClassDescriptor captureThis = getDispatchReceiverParameterForConstructorCall(descriptor, closure);
810            if (captureThis != null) {
811                writeParameter(sw, JvmMethodParameterKind.OUTER, captureThis.getDefaultType());
812            }
813    
814            JetType captureReceiverType = closure != null ? closure.getCaptureReceiverType() : null;
815            if (captureReceiverType != null) {
816                writeParameter(sw, JvmMethodParameterKind.RECEIVER, captureReceiverType);
817            }
818    
819            ClassDescriptor containingDeclaration = descriptor.getContainingDeclaration();
820            if (containingDeclaration.getKind() == ClassKind.ENUM_CLASS || containingDeclaration.getKind() == ClassKind.ENUM_ENTRY) {
821                writeParameter(sw, JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL, KotlinBuiltIns.getInstance().getStringType());
822                writeParameter(sw, JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL, KotlinBuiltIns.getInstance().getIntType());
823            }
824    
825            if (closure == null) return;
826    
827            for (DeclarationDescriptor variableDescriptor : closure.getCaptureVariables().keySet()) {
828                Type type;
829                if (variableDescriptor instanceof VariableDescriptor && !(variableDescriptor instanceof PropertyDescriptor)) {
830                    Type sharedVarType = getSharedVarType(variableDescriptor);
831                    if (sharedVarType == null) {
832                        sharedVarType = mapType(((VariableDescriptor) variableDescriptor).getType());
833                    }
834                    type = sharedVarType;
835                }
836                else if (isLocalNamedFun(variableDescriptor)) {
837                    //noinspection CastConflictsWithInstanceof
838                    type = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) variableDescriptor);
839                }
840                else {
841                    type = null;
842                }
843    
844                if (type != null) {
845                    writeParameter(sw, JvmMethodParameterKind.CAPTURED_LOCAL_VARIABLE, type);
846                }
847            }
848    
849            ResolvedCall<ConstructorDescriptor> superCall = closure.getSuperCall();
850            // We may generate a slightly wrong signature for a local class / anonymous object in light classes mode but we don't care,
851            // because such classes are not accessible from the outside world
852            if (superCall != null && classBuilderMode == ClassBuilderMode.FULL) {
853                writeSuperConstructorCallParameters(sw, descriptor, superCall, captureThis != null);
854            }
855        }
856    
857        private void writeSuperConstructorCallParameters(
858                @NotNull BothSignatureWriter sw,
859                @NotNull ConstructorDescriptor descriptor,
860                @NotNull ResolvedCall<ConstructorDescriptor> superCall,
861                boolean hasOuter
862        ) {
863            ConstructorDescriptor superDescriptor = superCall.getResultingDescriptor();
864            List<ResolvedValueArgument> valueArguments = superCall.getValueArgumentsByIndex();
865            assert valueArguments != null : "Failed to arrange value arguments by index: " + superDescriptor;
866    
867            List<JvmMethodParameterSignature> parameters = mapSignature(superDescriptor).getValueParameters();
868    
869            int params = parameters.size();
870            int args = valueArguments.size();
871    
872            // Mapped parameters should consist of captured values plus all of valueArguments
873            assert params >= args :
874                    String.format("Incorrect number of mapped parameters vs arguments: %d < %d for %s", params, args, descriptor);
875    
876            // Include all captured values, i.e. those parameters for which there are no resolved value arguments
877            for (int i = 0; i < params - args; i++) {
878                JvmMethodParameterSignature parameter = parameters.get(i);
879                JvmMethodParameterKind kind = parameter.getKind();
880                if (kind == JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL) continue;
881                if (hasOuter && kind == JvmMethodParameterKind.OUTER) continue;
882    
883                writeParameter(sw, JvmMethodParameterKind.SUPER_CALL_PARAM, parameter.getAsmType());
884            }
885    
886            if (isAnonymousObject(descriptor.getContainingDeclaration())) {
887                // For anonymous objects, also add all real non-default value arguments passed to the super constructor
888                for (int i = 0; i < args; i++) {
889                    ResolvedValueArgument valueArgument = valueArguments.get(i);
890                    JvmMethodParameterSignature parameter = parameters.get(params - args + i);
891                    if (!(valueArgument instanceof DefaultValueArgument)) {
892                        writeParameter(sw, JvmMethodParameterKind.SUPER_CALL_PARAM, parameter.getAsmType());
893                    }
894                }
895            }
896        }
897    
898        @NotNull
899        public JvmMethodSignature mapScriptSignature(@NotNull ScriptDescriptor script, @NotNull List<ScriptDescriptor> importedScripts) {
900            BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD);
901    
902            sw.writeParametersStart();
903    
904            for (ScriptDescriptor importedScript : importedScripts) {
905                ClassDescriptor descriptor = bindingContext.get(CLASS_FOR_SCRIPT, importedScript);
906                assert descriptor != null : "Script not found: " + importedScript;
907                writeParameter(sw, descriptor.getDefaultType());
908            }
909    
910            for (ValueParameterDescriptor valueParameter : script.getScriptCodeDescriptor().getValueParameters()) {
911                writeParameter(sw, valueParameter.getType());
912            }
913    
914            writeVoidReturn(sw);
915    
916            return sw.makeJvmMethodSignature("<init>");
917        }
918    
919        @NotNull
920        public CallableMethod mapToCallableMethod(@NotNull ConstructorDescriptor descriptor) {
921            JvmMethodSignature method = mapSignature(descriptor);
922            ClassDescriptor container = descriptor.getContainingDeclaration();
923            Type owner = mapClass(container);
924            if (owner.getSort() != Type.OBJECT) {
925                throw new IllegalStateException("type must have been mapped to object: " + container.getDefaultType() + ", actual: " + owner);
926            }
927            return new CallableMethod(owner, owner, owner, method, INVOKESPECIAL, null, null, null);
928        }
929    
930        public Type getSharedVarType(DeclarationDescriptor descriptor) {
931            if (descriptor instanceof SimpleFunctionDescriptor && descriptor.getContainingDeclaration() instanceof FunctionDescriptor) {
932                return asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor);
933            }
934            else if (descriptor instanceof PropertyDescriptor || descriptor instanceof FunctionDescriptor) {
935                ReceiverParameterDescriptor receiverParameter = ((CallableDescriptor) descriptor).getExtensionReceiverParameter();
936                assert receiverParameter != null : "Callable should have a receiver parameter: " + descriptor;
937                return StackValue.sharedTypeForType(mapType(receiverParameter.getType()));
938            }
939            else if (descriptor instanceof VariableDescriptor && isVarCapturedInClosure(bindingContext, descriptor)) {
940                return StackValue.sharedTypeForType(mapType(((VariableDescriptor) descriptor).getType()));
941            }
942            return null;
943        }
944    
945        // TODO Temporary hack until modules infrastructure is implemented. See JetTypeMapperWithOutDirectory for details
946        @Nullable
947        protected File getOutDirectory() {
948            return null;
949        }
950    }