Micro optimizations to type rendering in DescriptorRendererImpl

Do not create StringBuilder instances when the resulting String will be
appended to some other StringBuilder anyway. This, and a couple of micro
FqNameUnsafe-related optimizations, helps reduce memory traffic in Kotlin
reflection when rendering is involved (toString() is called on reflective
objects)
This commit is contained in:
Alexander Udalov
2016-08-12 20:08:20 +03:00
parent 3298649bd7
commit 26156b137f
3 changed files with 97 additions and 94 deletions
@@ -65,11 +65,11 @@ private val KotlinType.isTypeAnnotatedWithExtensionFunctionType: Boolean
* e.g. kotlin.Function1 (but NOT kotlin.reflect.KFunction1) * e.g. kotlin.Function1 (but NOT kotlin.reflect.KFunction1)
*/ */
fun isNumberedFunctionClassFqName(fqName: FqNameUnsafe): Boolean { fun isNumberedFunctionClassFqName(fqName: FqNameUnsafe): Boolean {
if (!fqName.startsWith(KotlinBuiltIns.BUILT_INS_PACKAGE_NAME)) return false
val segments = fqName.pathSegments() val segments = fqName.pathSegments()
if (segments.size != 2) return false if (segments.size != 2) return false
if (KotlinBuiltIns.BUILT_INS_PACKAGE_NAME != segments.first()) return false
val shortName = segments.last().asString() val shortName = segments.last().asString()
return BuiltInFictitiousFunctionClassFactory.isFunctionClassName(shortName, KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME) return BuiltInFictitiousFunctionClassFactory.isFunctionClassName(shortName, KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME)
} }
@@ -23,13 +23,21 @@ import org.jetbrains.annotations.Nullable;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.regex.Pattern;
/** /**
* Like {@link FqName} but allows '<' and '>' characters in name. * Like {@link FqName} but allows '<' and '>' characters in name.
*/ */
public final class FqNameUnsafe { public final class FqNameUnsafe {
private static final Name ROOT_NAME = Name.special("<root>");
private static final Pattern SPLIT_BY_DOTS = Pattern.compile("\\.");
public static final Name ROOT_NAME = Name.special("<root>"); private static final Function1<String, Name> STRING_TO_NAME = new Function1<String, Name>() {
@Override
public Name invoke(String name) {
return Name.guessByFirstCharacter(name);
}
};
@NotNull @NotNull
private final String fqName; private final String fqName;
@@ -147,17 +155,12 @@ public final class FqNameUnsafe {
@NotNull @NotNull
public List<Name> pathSegments() { public List<Name> pathSegments() {
return isRoot() ? Collections.<Name>emptyList() : return isRoot() ? Collections.<Name>emptyList() : ArraysKt.map(SPLIT_BY_DOTS.split(fqName), STRING_TO_NAME);
ArraysKt.map(fqName.split("\\."), new Function1<String, Name>() {
@Override
public Name invoke(String name) {
return Name.guessByFirstCharacter(name);
}
});
} }
public boolean startsWith(@NotNull Name segment) { public boolean startsWith(@NotNull Name segment) {
return !isRoot() && pathSegments().get(0).equals(segment); int firstDot = fqName.indexOf('.');
return !isRoot() && fqName.regionMatches(0, segment.asString(), 0, firstDot == -1 ? fqName.length() : firstDot);
} }
@NotNull @NotNull
@@ -118,52 +118,62 @@ internal class DescriptorRendererImpl(
} }
/* TYPES RENDERING */ /* TYPES RENDERING */
override fun renderType(type: KotlinType): String { override fun renderType(type: KotlinType): String = buildString {
return renderNormalizedType(typeNormalizer(type)) renderNormalizedType(typeNormalizer(type))
} }
private fun renderNormalizedType(type: KotlinType): String { private fun StringBuilder.renderNormalizedType(type: KotlinType) {
val abbreviated = (type.unwrap() as? AbbreviatedType) val abbreviated = type.unwrap() as? AbbreviatedType
if (abbreviated != null) { if (abbreviated != null) {
// TODO nullability is lost for abbreviated type? // TODO nullability is lost for abbreviated type?
val abbreviatedRendered = renderNormalizedTypeAsIs(abbreviated.abbreviation) renderNormalizedTypeAsIs(abbreviated.abbreviation)
if (!renderUnabbreviatedType) return abbreviatedRendered if (renderUnabbreviatedType) {
val unabbreviatedRendered = renderNormalizedTypeAsIs(abbreviated.expandedType) append(" /* = ")
return "$abbreviatedRendered /* = $unabbreviatedRendered */" renderNormalizedTypeAsIs(abbreviated.expandedType)
append(" */")
}
return
} }
return renderNormalizedTypeAsIs(type) renderNormalizedTypeAsIs(type)
} }
private fun renderNormalizedTypeAsIs(type: KotlinType): String { private fun StringBuilder.renderNormalizedTypeAsIs(type: KotlinType) {
if (type is WrappedType && debugMode && !type.isComputed()) { if (type is WrappedType && debugMode && !type.isComputed()) {
return "<Not computed yet>" append("<Not computed yet>")
return
} }
val unwrappedType = type.unwrap() val unwrappedType = type.unwrap()
return when (unwrappedType) { when (unwrappedType) {
is FlexibleType -> unwrappedType.render(this, this) is FlexibleType -> append(unwrappedType.render(this@DescriptorRendererImpl, this@DescriptorRendererImpl))
is SimpleType -> renderSimpleType(unwrappedType) is SimpleType -> renderSimpleType(unwrappedType)
} }
} }
private fun renderSimpleType(type: SimpleType): String { private fun StringBuilder.renderSimpleType(type: SimpleType) {
if (type == CANT_INFER_FUNCTION_PARAM_TYPE || TypeUtils.isDontCarePlaceholder(type)) { if (type == CANT_INFER_FUNCTION_PARAM_TYPE || TypeUtils.isDontCarePlaceholder(type)) {
return "???" append("???")
return
} }
if (ErrorUtils.isUninferredParameter(type)) { if (ErrorUtils.isUninferredParameter(type)) {
if (uninferredTypeParameterAsName) { if (uninferredTypeParameterAsName) {
return renderError((type.constructor as UninferredParameterTypeConstructor).typeParameterDescriptor.name.toString()) append(renderError((type.constructor as UninferredParameterTypeConstructor).typeParameterDescriptor.name.toString()))
} }
return "???" else {
append("???")
}
return
} }
if (type.isError) { if (type.isError) {
return renderDefaultType(type) renderDefaultType(type)
return
} }
if (shouldRenderAsPrettyFunctionType(type)) { if (shouldRenderAsPrettyFunctionType(type)) {
return renderFunctionType(type) renderFunctionType(type)
}
else {
renderDefaultType(type)
} }
return renderDefaultType(type)
} }
private fun shouldRenderAsPrettyFunctionType(type: KotlinType): Boolean { private fun shouldRenderAsPrettyFunctionType(type: KotlinType): Boolean {
@@ -200,58 +210,50 @@ internal class DescriptorRendererImpl(
if (typeArguments.isEmpty()) return "" if (typeArguments.isEmpty()) return ""
return buildString { return buildString {
append(lt()) append(lt())
appendTypeProjections(typeArguments, this) this.appendTypeProjections(typeArguments)
append(gt()) append(gt())
} }
} }
private fun renderDefaultType(type: KotlinType): String { private fun StringBuilder.renderDefaultType(type: KotlinType) {
val sb = StringBuilder() renderAnnotations(type, this)
renderAnnotations(type, sb)
if (type.isError) { if (type.isError) {
sb.append(type.constructor.toString()) // Debug name of an error type is more informative append(type.constructor.toString()) // Debug name of an error type is more informative
sb.append(renderTypeArguments(type.arguments)) append(renderTypeArguments(type.arguments))
} }
else { else {
sb.append(renderTypeConstructorAndArguments(type)) renderTypeConstructorAndArguments(type)
} }
if (type.isMarkedNullable) { if (type.isMarkedNullable) {
sb.append("?") append("?")
} }
return sb.toString()
} }
private fun renderTypeConstructorAndArguments( private fun StringBuilder.renderTypeConstructorAndArguments(
type: KotlinType, type: KotlinType,
typeConstructor: TypeConstructor = type.constructor typeConstructor: TypeConstructor = type.constructor
): String = ) {
buildString { val possiblyInnerType = type.buildPossiblyInnerType()
if (possiblyInnerType == null) {
val possiblyInnerType = type.buildPossiblyInnerType() append(renderTypeConstructor(typeConstructor))
if (possiblyInnerType == null) { append(renderTypeArguments(type.arguments))
append(renderTypeConstructor(typeConstructor)) return
append(renderTypeArguments(type.arguments))
return@buildString
}
append(renderPossiblyInnerType(possiblyInnerType))
} }
private fun renderPossiblyInnerType(possiblyInnerType: PossiblyInnerType): String = renderPossiblyInnerType(possiblyInnerType)
buildString { }
possiblyInnerType.outerType?.let {
append(renderPossiblyInnerType(it))
append('.')
append(renderName(possiblyInnerType.classifierDescriptor.name))
} ?: append(renderTypeConstructor(possiblyInnerType.classifierDescriptor.typeConstructor))
append(renderTypeArguments(possiblyInnerType.arguments))
}
private fun StringBuilder.renderPossiblyInnerType(possiblyInnerType: PossiblyInnerType) {
possiblyInnerType.outerType?.let {
renderPossiblyInnerType(it)
append('.')
append(renderName(possiblyInnerType.classifierDescriptor.name))
} ?: append(renderTypeConstructor(possiblyInnerType.classifierDescriptor.typeConstructor))
append(renderTypeArguments(possiblyInnerType.arguments))
}
override fun renderTypeConstructor(typeConstructor: TypeConstructor): String { override fun renderTypeConstructor(typeConstructor: TypeConstructor): String {
val cd = typeConstructor.declarationDescriptor val cd = typeConstructor.declarationDescriptor
@@ -263,10 +265,10 @@ internal class DescriptorRendererImpl(
} }
override fun renderTypeProjection(typeProjection: TypeProjection) = buildString { override fun renderTypeProjection(typeProjection: TypeProjection) = buildString {
appendTypeProjections(listOf(typeProjection), this) appendTypeProjections(listOf(typeProjection))
} }
private fun appendTypeProjections(typeProjections: List<TypeProjection>, builder: StringBuilder) { private fun StringBuilder.appendTypeProjections(typeProjections: List<TypeProjection>) {
typeProjections.map { typeProjections.map {
if (it.isStarProjection) { if (it.isStarProjection) {
"*" "*"
@@ -275,52 +277,50 @@ internal class DescriptorRendererImpl(
val type = renderType(it.type) val type = renderType(it.type)
if (it.projectionKind == Variance.INVARIANT) type else "${it.projectionKind} $type" if (it.projectionKind == Variance.INVARIANT) type else "${it.projectionKind} $type"
} }
}.joinTo(builder, ", ") }.joinTo(this, ", ")
} }
private fun renderFunctionType(type: KotlinType): String { private fun StringBuilder.renderFunctionType(type: KotlinType) {
return buildString { val isNullable = type.isMarkedNullable
val isNullable = type.isMarkedNullable if (isNullable) append("(")
if (isNullable) append("(")
val receiverType = getReceiverTypeFromFunctionType(type) val receiverType = getReceiverTypeFromFunctionType(type)
if (receiverType != null) { if (receiverType != null) {
val surroundReceiver = shouldRenderAsPrettyFunctionType(receiverType) && !receiverType.isMarkedNullable val surroundReceiver = shouldRenderAsPrettyFunctionType(receiverType) && !receiverType.isMarkedNullable
if (surroundReceiver) { if (surroundReceiver) {
append("(") append("(")
}
append(renderNormalizedType(receiverType))
if (surroundReceiver) {
append(")")
}
append(".")
} }
renderNormalizedType(receiverType)
append("(") if (surroundReceiver) {
appendTypeProjections(getValueParameterTypesFromFunctionType(type), this) append(")")
append(") ").append(arrow()).append(" ") }
append(renderNormalizedType(getReturnTypeFromFunctionType(type))) append(".")
if (isNullable) append(")?")
} }
append("(")
appendTypeProjections(getValueParameterTypesFromFunctionType(type))
append(") ").append(arrow()).append(" ")
renderNormalizedType(getReturnTypeFromFunctionType(type))
if (isNullable) append(")?")
} }
/* METHODS FOR ALL KINDS OF DESCRIPTORS */ /* METHODS FOR ALL KINDS OF DESCRIPTORS */
private fun appendDefinedIn(descriptor: DeclarationDescriptor, builder: StringBuilder) { private fun StringBuilder.appendDefinedIn(descriptor: DeclarationDescriptor) {
if (descriptor is PackageFragmentDescriptor || descriptor is PackageViewDescriptor) { if (descriptor is PackageFragmentDescriptor || descriptor is PackageViewDescriptor) {
return return
} }
if (descriptor is ModuleDescriptor) { if (descriptor is ModuleDescriptor) {
builder.append(" is a module") append(" is a module")
return return
} }
val containingDeclaration = descriptor.containingDeclaration val containingDeclaration = descriptor.containingDeclaration
if (containingDeclaration != null && containingDeclaration !is ModuleDescriptor) { if (containingDeclaration != null && containingDeclaration !is ModuleDescriptor) {
builder.append(" ").append(renderMessage("defined in")).append(" ") append(" ").append(renderMessage("defined in")).append(" ")
val fqName = DescriptorUtils.getFqName(containingDeclaration) val fqName = DescriptorUtils.getFqName(containingDeclaration)
builder.append(if (fqName.isRoot) "root package" else renderFqName(fqName)) append(if (fqName.isRoot) "root package" else renderFqName(fqName))
} }
} }
private fun renderAnnotations(annotated: Annotated, builder: StringBuilder) { private fun renderAnnotations(annotated: Annotated, builder: StringBuilder) {
@@ -479,7 +479,7 @@ internal class DescriptorRendererImpl(
declarationDescriptor.accept(RenderDeclarationDescriptorVisitor(), this) declarationDescriptor.accept(RenderDeclarationDescriptorVisitor(), this)
if (withDefinedIn) { if (withDefinedIn) {
appendDefinedIn(declarationDescriptor, this) appendDefinedIn(declarationDescriptor)
} }
} }
} }