Inlining package members should use facade class for SMAP.

This commit is contained in:
Dmitry Petrov
2015-09-29 13:20:59 +03:00
parent 9a41ee41d7
commit c17326841a
4 changed files with 117 additions and 90 deletions
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.renderer.DescriptorRenderer; import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.inline.InlineStrategy; import org.jetbrains.kotlin.resolve.inline.InlineStrategy;
import org.jetbrains.kotlin.resolve.inline.InlineUtil; import org.jetbrains.kotlin.resolve.inline.InlineUtil;
@@ -69,7 +70,6 @@ import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.getConstant;
import static org.jetbrains.kotlin.codegen.inline.InlinePackage.getClassFilePath; import static org.jetbrains.kotlin.codegen.inline.InlinePackage.getClassFilePath;
import static org.jetbrains.kotlin.codegen.inline.InlinePackage.getSourceFilePath; import static org.jetbrains.kotlin.codegen.inline.InlinePackage.getSourceFilePath;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isFunctionLiteral; import static org.jetbrains.kotlin.resolve.DescriptorUtils.isFunctionLiteral;
import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getResolvedCallWithAssert;
public class InlineCodegen extends CallGenerator { public class InlineCodegen extends CallGenerator {
private final GenerationState state; private final GenerationState state;
@@ -193,18 +193,14 @@ public class InlineCodegen extends CallGenerator {
SMAPAndMethodNode nodeAndSMAP; SMAPAndMethodNode nodeAndSMAP;
if (functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) { if (functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) {
ClassId containerClassId = InlineCodegenUtil.getContainerClassIdForInlineCallable( JetTypeMapper.ContainingClassesInfo containingClasses = typeMapper.getContainerClassIdForInlineCallable(
(DeserializedSimpleFunctionDescriptor) functionDescriptor); (DeserializedSimpleFunctionDescriptor) functionDescriptor);
VirtualFile file = InlineCodegenUtil.getVirtualFileForCallable(containerClassId, state); VirtualFile file = InlineCodegenUtil.getVirtualFileForCallable(containingClasses.getImplClassId(), state);
//if (functionDescriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor) {
// /*use facade class*/
// containerClassId = PackageClassUtils.getPackageClassId(containerClassId.getPackageFqName());
//}
nodeAndSMAP = InlineCodegenUtil.getMethodNode(file.contentsToByteArray(), nodeAndSMAP = InlineCodegenUtil.getMethodNode(file.contentsToByteArray(),
asmMethod.getName(), asmMethod.getName(),
asmMethod.getDescriptor(), asmMethod.getDescriptor(),
containerClassId); containingClasses.getFacadeClassId());
if (nodeAndSMAP == null) { if (nodeAndSMAP == null) {
throw new RuntimeException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor)); throw new RuntimeException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor));
@@ -231,7 +227,7 @@ public class InlineCodegen extends CallGenerator {
SMAP smap; SMAP smap;
if (callDefault) { if (callDefault) {
Type implementationOwner = typeMapper.mapImplementationOwner(functionDescriptor); Type implementationOwner = typeMapper.mapOwner(functionDescriptor);
FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen(), inliningFunction, FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen(), inliningFunction,
(FieldOwnerContext) methodContext.getParentContext(), (FieldOwnerContext) methodContext.getParentContext(),
implementationOwner.getInternalName()); implementationOwner.getInternalName());
@@ -343,15 +339,15 @@ public class InlineCodegen extends CallGenerator {
new FakeMemberCodegen(codegen.getParentCodegen(), expression, new FakeMemberCodegen(codegen.getParentCodegen(), expression,
(FieldOwnerContext) context.getParentContext(), (FieldOwnerContext) context.getParentContext(),
isLambda ? codegen.getParentCodegen().getClassName() isLambda ? codegen.getParentCodegen().getClassName()
: typeMapper.mapImplementationOwner(descriptor).getInternalName()); : typeMapper.mapOwner(descriptor).getInternalName());
FunctionGenerationStrategy strategy = FunctionGenerationStrategy strategy =
expression instanceof JetCallableReferenceExpression ? expression instanceof JetCallableReferenceExpression ?
new FunctionReferenceGenerationStrategy( new FunctionReferenceGenerationStrategy(
state, state,
descriptor, descriptor,
getResolvedCallWithAssert(((JetCallableReferenceExpression) expression).getCallableReference(), CallUtilKt.getResolvedCallWithAssert(((JetCallableReferenceExpression) expression).getCallableReference(),
codegen.getBindingContext() codegen.getBindingContext()
)) : )) :
new FunctionGenerationStrategy.FunctionDefault(state, descriptor, (JetDeclarationWithBody) expression); new FunctionGenerationStrategy.FunctionDefault(state, descriptor, (JetDeclarationWithBody) expression);
@@ -154,25 +154,6 @@ public class InlineCodegenUtil {
return file; return file;
} }
public static ClassId getContainerClassIdForInlineCallable(DeserializedSimpleFunctionDescriptor deserializedDescriptor) {
DeclarationDescriptor parentDeclaration = deserializedDescriptor.getContainingDeclaration();
ClassId containerClassId;
if (parentDeclaration instanceof PackageFragmentDescriptor) {
ProtoBuf.Callable proto = deserializedDescriptor.getProto();
if (!proto.hasExtension(JvmProtoBuf.implClassName)) {
throw new IllegalStateException("Function in namespace should have implClassName property in proto: " + deserializedDescriptor);
}
Name name = deserializedDescriptor.getNameResolver().getName(proto.getExtension(JvmProtoBuf.implClassName));
containerClassId = new ClassId(((PackageFragmentDescriptor) parentDeclaration).getFqName(), name);
} else {
containerClassId = getContainerClassId(deserializedDescriptor);
}
if (containerClassId == null) {
throw new IllegalStateException("Couldn't find container FQName for " + deserializedDescriptor.getName());
}
return containerClassId;
}
@Nullable @Nullable
public static VirtualFile findVirtualFile(@NotNull Project project, @NotNull String internalClassName) { public static VirtualFile findVirtualFile(@NotNull Project project, @NotNull String internalClassName) {
FqName packageFqName = JvmClassName.byInternalName(internalClassName).getPackageFqName(); FqName packageFqName = JvmClassName.byInternalName(internalClassName).getPackageFqName();
@@ -28,9 +28,10 @@ import org.jetbrains.kotlin.codegen.*;
import org.jetbrains.kotlin.codegen.binding.CodegenBinding; import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
import org.jetbrains.kotlin.codegen.binding.MutableClosure; import org.jetbrains.kotlin.codegen.binding.MutableClosure;
import org.jetbrains.kotlin.codegen.binding.PsiCodegenPredictor; import org.jetbrains.kotlin.codegen.binding.PsiCodegenPredictor;
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter; import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.fileClasses.FileClassesPackage; import org.jetbrains.kotlin.fileClasses.FileClasses;
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil; import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil;
import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider; import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider;
import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.java.JvmAbi;
@@ -63,6 +64,8 @@ import org.jetbrains.kotlin.resolve.scopes.AbstractScopeAdapter;
import org.jetbrains.kotlin.resolve.scopes.JetScope; import org.jetbrains.kotlin.resolve.scopes.JetScope;
import org.jetbrains.kotlin.serialization.deserialization.DeserializedType; import org.jetbrains.kotlin.serialization.deserialization.DeserializedType;
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor; import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor;
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor;
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf;
import org.jetbrains.kotlin.types.*; import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.expressions.OperatorConventions; import org.jetbrains.kotlin.types.expressions.OperatorConventions;
import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.Type;
@@ -144,11 +147,6 @@ public class JetTypeMapper {
return mapOwner(descriptor, false); return mapOwner(descriptor, false);
} }
@NotNull
public Type mapImplementationOwner(@NotNull DeclarationDescriptor descriptor) {
return mapOwner(descriptor, true);
}
@NotNull @NotNull
private Type mapOwner(@NotNull DeclarationDescriptor descriptor, boolean isImplementation) { private Type mapOwner(@NotNull DeclarationDescriptor descriptor, boolean isImplementation) {
if (isLocalFunction(descriptor)) { if (isLocalFunction(descriptor)) {
@@ -176,17 +174,17 @@ public class JetTypeMapper {
if (file != null) { if (file != null) {
Visibility visibility = descriptor.getVisibility(); Visibility visibility = descriptor.getVisibility();
if (isImplementation || descriptor instanceof PropertyDescriptor || Visibilities.isPrivate(visibility)) { if (isImplementation || descriptor instanceof PropertyDescriptor || Visibilities.isPrivate(visibility)) {
return FileClassesPackage.getFileClassInternalName(fileClassesProvider, file); return FileClasses.getFileClassInternalName(fileClassesProvider, file);
} }
else { else {
return FileClassesPackage.getFacadeClassInternalName(fileClassesProvider, file); return FileClasses.getFacadeClassInternalName(fileClassesProvider, file);
} }
} }
CallableMemberDescriptor directMember = getDirectMember(descriptor); CallableMemberDescriptor directMember = getDirectMember(descriptor);
if (directMember instanceof DeserializedCallableMemberDescriptor) { if (directMember instanceof DeserializedCallableMemberDescriptor) {
String facadeFqName = getPackageMemberOwnerInternalName((DeserializedCallableMemberDescriptor) directMember, isImplementation); String facadeFqName = getPackageMemberOwnerInternalName((DeserializedCallableMemberDescriptor) directMember);
if (facadeFqName != null) return facadeFqName; if (facadeFqName != null) return facadeFqName;
} }
@@ -194,69 +192,120 @@ public class JetTypeMapper {
//return PackageClassUtils.getPackageClassInternalName(packageFragment.getFqName()); //return PackageClassUtils.getPackageClassInternalName(packageFragment.getFqName());
} }
@Nullable public static class ContainingClassesInfo {
private String getPackageMemberOwnerInternalName(@NotNull DeserializedCallableMemberDescriptor descriptor, boolean isImplementation) { private final ClassId facadeClassId;
// XXX This method (and getPackageMemberOwnerShortName) is a dirty hack private final ClassId implClassId;
// introduced to make stdlib work with package facades built as multifile facades for M13.
// We need some safe, concise way to identify multifile facade and multifile part
// from a deserialized package member descriptor.
// Possible approaches:
// - create a special instance of DeserializedPackageFragmentDescriptor for each facade class (multifile or single-file),
// keep related mapping information there;
// - provide a proper SourceElement for such descriptors (similar to KotlinJvmBinarySourceElement).
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
assert containingDeclaration instanceof PackageFragmentDescriptor : "Not a top-level member: " + descriptor;
PackageFragmentDescriptor packageFragmentDescriptor = (PackageFragmentDescriptor) containingDeclaration;
String facadeShortName = getPackageMemberOwnerShortName(descriptor, isImplementation); public ContainingClassesInfo(ClassId facadeClassId, ClassId implClassId) {
if (facadeShortName == null) { this.facadeClassId = facadeClassId;
return null; this.implClassId = implClassId;
} }
FqName facadeFqName = packageFragmentDescriptor.getFqName().child(Name.identifier(facadeShortName)); public ClassId getFacadeClassId() {
return internalNameByFqNameWithoutInnerClasses(facadeFqName); return facadeClassId;
}
public ClassId getImplClassId() {
return implClassId;
}
private static @Nullable ContainingClassesInfo forPackageMemberOrNull(
@NotNull FqName packageFqName,
@Nullable String facadeClassName,
@Nullable String implClassName
) {
if (facadeClassName == null || implClassName == null) {
return null;
}
return new ContainingClassesInfo(ClassId.topLevel(packageFqName.child(Name.identifier(facadeClassName))),
ClassId.topLevel(packageFqName.child(Name.identifier(implClassName))));
}
private static @Nullable ContainingClassesInfo forClassMemberOrNull(@Nullable ClassId classId) {
if (classId == null) {
return null;
}
return new ContainingClassesInfo(classId, classId);
}
}
public ContainingClassesInfo getContainerClassIdForInlineCallable(DeserializedSimpleFunctionDescriptor deserializedDescriptor) {
DeclarationDescriptor parentDeclaration = deserializedDescriptor.getContainingDeclaration();
ContainingClassesInfo containingClassesInfo;
if (parentDeclaration instanceof PackageFragmentDescriptor) {
containingClassesInfo = getPackageMemberContainingClassesInfo(deserializedDescriptor);
} else {
containingClassesInfo = ContainingClassesInfo.forClassMemberOrNull(
InlineCodegenUtil.getContainerClassId(deserializedDescriptor));
}
if (containingClassesInfo == null) {
throw new IllegalStateException("Couldn't find container for " + deserializedDescriptor.getName());
}
return containingClassesInfo;
} }
@Nullable @Nullable
private String getPackageMemberOwnerShortName(@NotNull DeserializedCallableMemberDescriptor descriptor, boolean isImplementation) { private String getPackageMemberOwnerInternalName(@NotNull DeserializedCallableMemberDescriptor descriptor) {
// XXX Dirty hack; see getPackageMemberOwnerInternalName above for more details.
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (containingDeclaration instanceof PackageFragmentDescriptor) { assert containingDeclaration instanceof PackageFragmentDescriptor : "Not a top-level member: " + descriptor;
Name implClassName = JvmFileClassUtil.getImplClassName(descriptor);
if (isImplementation) {
return implClassName.asString();
}
PackageFragmentDescriptor packageFragmentDescriptor = (PackageFragmentDescriptor) containingDeclaration; ContainingClassesInfo containingClasses = getPackageMemberContainingClassesInfo(descriptor);
JetScope scope = packageFragmentDescriptor.getMemberScope(); if (containingClasses == null) {
if (scope instanceof AbstractScopeAdapter) { return null;
scope = ((AbstractScopeAdapter) scope).getActualScope(); }
}
if (scope instanceof LazyJavaPackageScope) {
return ((LazyJavaPackageScope) scope).getFacadeSimpleNameForPartSimpleName(implClassName.asString());
}
else if (packageFragmentDescriptor instanceof BuiltinsPackageFragment) {
return PackageClassUtils.getPackageClassFqName(packageFragmentDescriptor.getFqName()).shortName().asString();
}
else if (packageFragmentDescriptor instanceof IncrementalPackageFragmentProvider.IncrementalPackageFragment) {
assert incrementalCache != null : "IncrementalPackageFragment found outside of incremental compilation context " +
"for " + descriptor + " in package " + packageFragmentDescriptor;
String implClassInternalName = internalNameByFqNameWithoutInnerClasses( return JvmClassName.byClassId(containingClasses.getFacadeClassId()).getInternalName();
packageFragmentDescriptor.getFqName().child(implClassName)); }
String facadeClassInternalName = incrementalCache.getMultifileFacade(implClassInternalName);
if (facadeClassInternalName == null) { @Nullable
return implClassName.asString(); private ContainingClassesInfo getPackageMemberContainingClassesInfo(@NotNull DeserializedCallableMemberDescriptor descriptor) {
} // XXX This method (and getPackageMemberOwnerShortName) is a dirty hack.
else { // We need some safe, concise way to identify multifile facade and multifile part
return getSimpleInternalName(facadeClassInternalName); // from a deserialized package member descriptor.
} DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
assert containingDeclaration instanceof PackageFragmentDescriptor
: "Package member expected, got " + descriptor + " in " + containingDeclaration;
PackageFragmentDescriptor packageFragmentDescriptor = (PackageFragmentDescriptor) containingDeclaration;
if (packageFragmentDescriptor instanceof BuiltinsPackageFragment) {
ClassId builtinsFacadeClassId = ClassId.topLevel(PackageClassUtils.getPackageClassFqName(packageFragmentDescriptor.getFqName()));
return new ContainingClassesInfo(builtinsFacadeClassId, builtinsFacadeClassId);
}
assert descriptor.getProto().hasExtension(JvmProtoBuf.implClassName)
: "No implClassName for " + descriptor;
Name implClassName = JvmFileClassUtil.getImplClassName(descriptor);
String implSimpleName = implClassName.asString();
String facadeSimpleName;
JetScope scope = packageFragmentDescriptor.getMemberScope();
if (scope instanceof AbstractScopeAdapter) {
scope = ((AbstractScopeAdapter) scope).getActualScope();
}
if (scope instanceof LazyJavaPackageScope) {
facadeSimpleName = ((LazyJavaPackageScope) scope).getFacadeSimpleNameForPartSimpleName(implClassName.asString());
}
else if (packageFragmentDescriptor instanceof IncrementalPackageFragmentProvider.IncrementalPackageFragment) {
assert incrementalCache != null
: "IncrementalPackageFragment found outside of incremental compilation context " +
"for " + descriptor + " in package " + packageFragmentDescriptor;
String implClassInternalName = internalNameByFqNameWithoutInnerClasses(
packageFragmentDescriptor.getFqName().child(implClassName));
String facadeClassInternalName = incrementalCache.getMultifileFacade(implClassInternalName);
if (facadeClassInternalName == null) {
facadeSimpleName = implClassName.asString();
} }
else { else {
return implClassName.asString(); facadeSimpleName = getSimpleInternalName(facadeClassInternalName);
} }
} }
return null; else {
throw new AssertionError("Unexpected package member scope for " + descriptor + ": " +
scope + " :" + scope.getClass().getSimpleName());
}
return ContainingClassesInfo.forPackageMemberOrNull(packageFragmentDescriptor.getFqName(), facadeSimpleName, implSimpleName);
} }
@NotNull @NotNull
@@ -14,6 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
@file:JvmName("FileClasses")
package org.jetbrains.kotlin.fileClasses package org.jetbrains.kotlin.fileClasses
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName