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 }