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 }