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.resolve.DescriptorToSourceUtils;
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.inline.InlineStrategy;
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.getSourceFilePath;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isFunctionLiteral;
import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getResolvedCallWithAssert;
public class InlineCodegen extends CallGenerator {
private final GenerationState state;
@@ -193,18 +193,14 @@ public class InlineCodegen extends CallGenerator {
SMAPAndMethodNode nodeAndSMAP;
if (functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) {
ClassId containerClassId = InlineCodegenUtil.getContainerClassIdForInlineCallable(
JetTypeMapper.ContainingClassesInfo containingClasses = typeMapper.getContainerClassIdForInlineCallable(
(DeserializedSimpleFunctionDescriptor) functionDescriptor);
VirtualFile file = InlineCodegenUtil.getVirtualFileForCallable(containerClassId, state);
//if (functionDescriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor) {
// /*use facade class*/
// containerClassId = PackageClassUtils.getPackageClassId(containerClassId.getPackageFqName());
//}
VirtualFile file = InlineCodegenUtil.getVirtualFileForCallable(containingClasses.getImplClassId(), state);
nodeAndSMAP = InlineCodegenUtil.getMethodNode(file.contentsToByteArray(),
asmMethod.getName(),
asmMethod.getDescriptor(),
containerClassId);
containingClasses.getFacadeClassId());
if (nodeAndSMAP == null) {
throw new RuntimeException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor));
@@ -231,7 +227,7 @@ public class InlineCodegen extends CallGenerator {
SMAP smap;
if (callDefault) {
Type implementationOwner = typeMapper.mapImplementationOwner(functionDescriptor);
Type implementationOwner = typeMapper.mapOwner(functionDescriptor);
FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen(), inliningFunction,
(FieldOwnerContext) methodContext.getParentContext(),
implementationOwner.getInternalName());
@@ -343,15 +339,15 @@ public class InlineCodegen extends CallGenerator {
new FakeMemberCodegen(codegen.getParentCodegen(), expression,
(FieldOwnerContext) context.getParentContext(),
isLambda ? codegen.getParentCodegen().getClassName()
: typeMapper.mapImplementationOwner(descriptor).getInternalName());
: typeMapper.mapOwner(descriptor).getInternalName());
FunctionGenerationStrategy strategy =
expression instanceof JetCallableReferenceExpression ?
new FunctionReferenceGenerationStrategy(
state,
descriptor,
getResolvedCallWithAssert(((JetCallableReferenceExpression) expression).getCallableReference(),
codegen.getBindingContext()
CallUtilKt.getResolvedCallWithAssert(((JetCallableReferenceExpression) expression).getCallableReference(),
codegen.getBindingContext()
)) :
new FunctionGenerationStrategy.FunctionDefault(state, descriptor, (JetDeclarationWithBody) expression);
@@ -154,25 +154,6 @@ public class InlineCodegenUtil {
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
public static VirtualFile findVirtualFile(@NotNull Project project, @NotNull String internalClassName) {
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.MutableClosure;
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.descriptors.*;
import org.jetbrains.kotlin.fileClasses.FileClassesPackage;
import org.jetbrains.kotlin.fileClasses.FileClasses;
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil;
import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider;
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.serialization.deserialization.DeserializedType;
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.expressions.OperatorConventions;
import org.jetbrains.org.objectweb.asm.Type;
@@ -144,11 +147,6 @@ public class JetTypeMapper {
return mapOwner(descriptor, false);
}
@NotNull
public Type mapImplementationOwner(@NotNull DeclarationDescriptor descriptor) {
return mapOwner(descriptor, true);
}
@NotNull
private Type mapOwner(@NotNull DeclarationDescriptor descriptor, boolean isImplementation) {
if (isLocalFunction(descriptor)) {
@@ -176,17 +174,17 @@ public class JetTypeMapper {
if (file != null) {
Visibility visibility = descriptor.getVisibility();
if (isImplementation || descriptor instanceof PropertyDescriptor || Visibilities.isPrivate(visibility)) {
return FileClassesPackage.getFileClassInternalName(fileClassesProvider, file);
return FileClasses.getFileClassInternalName(fileClassesProvider, file);
}
else {
return FileClassesPackage.getFacadeClassInternalName(fileClassesProvider, file);
return FileClasses.getFacadeClassInternalName(fileClassesProvider, file);
}
}
CallableMemberDescriptor directMember = getDirectMember(descriptor);
if (directMember instanceof DeserializedCallableMemberDescriptor) {
String facadeFqName = getPackageMemberOwnerInternalName((DeserializedCallableMemberDescriptor) directMember, isImplementation);
String facadeFqName = getPackageMemberOwnerInternalName((DeserializedCallableMemberDescriptor) directMember);
if (facadeFqName != null) return facadeFqName;
}
@@ -194,69 +192,120 @@ public class JetTypeMapper {
//return PackageClassUtils.getPackageClassInternalName(packageFragment.getFqName());
}
@Nullable
private String getPackageMemberOwnerInternalName(@NotNull DeserializedCallableMemberDescriptor descriptor, boolean isImplementation) {
// XXX This method (and getPackageMemberOwnerShortName) is a dirty hack
// 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;
public static class ContainingClassesInfo {
private final ClassId facadeClassId;
private final ClassId implClassId;
String facadeShortName = getPackageMemberOwnerShortName(descriptor, isImplementation);
if (facadeShortName == null) {
return null;
public ContainingClassesInfo(ClassId facadeClassId, ClassId implClassId) {
this.facadeClassId = facadeClassId;
this.implClassId = implClassId;
}
FqName facadeFqName = packageFragmentDescriptor.getFqName().child(Name.identifier(facadeShortName));
return internalNameByFqNameWithoutInnerClasses(facadeFqName);
public ClassId getFacadeClassId() {
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
private String getPackageMemberOwnerShortName(@NotNull DeserializedCallableMemberDescriptor descriptor, boolean isImplementation) {
// XXX Dirty hack; see getPackageMemberOwnerInternalName above for more details.
private String getPackageMemberOwnerInternalName(@NotNull DeserializedCallableMemberDescriptor descriptor) {
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (containingDeclaration instanceof PackageFragmentDescriptor) {
Name implClassName = JvmFileClassUtil.getImplClassName(descriptor);
if (isImplementation) {
return implClassName.asString();
}
assert containingDeclaration instanceof PackageFragmentDescriptor : "Not a top-level member: " + descriptor;
PackageFragmentDescriptor packageFragmentDescriptor = (PackageFragmentDescriptor) containingDeclaration;
JetScope scope = packageFragmentDescriptor.getMemberScope();
if (scope instanceof AbstractScopeAdapter) {
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;
ContainingClassesInfo containingClasses = getPackageMemberContainingClassesInfo(descriptor);
if (containingClasses == null) {
return null;
}
String implClassInternalName = internalNameByFqNameWithoutInnerClasses(
packageFragmentDescriptor.getFqName().child(implClassName));
String facadeClassInternalName = incrementalCache.getMultifileFacade(implClassInternalName);
if (facadeClassInternalName == null) {
return implClassName.asString();
}
else {
return getSimpleInternalName(facadeClassInternalName);
}
return JvmClassName.byClassId(containingClasses.getFacadeClassId()).getInternalName();
}
@Nullable
private ContainingClassesInfo getPackageMemberContainingClassesInfo(@NotNull DeserializedCallableMemberDescriptor descriptor) {
// XXX This method (and getPackageMemberOwnerShortName) is a dirty hack.
// We need some safe, concise way to identify multifile facade and multifile part
// 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 {
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
@@ -14,6 +14,7 @@
* limitations under the License.
*/
@file:JvmName("FileClasses")
package org.jetbrains.kotlin.fileClasses
import org.jetbrains.kotlin.name.FqName