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