Use type table in DescriptorSerializer, add switch to enable/disable, test
This commit is contained in:
+120
-19
@@ -39,13 +39,21 @@ import java.util.*;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry;
|
||||
|
||||
public class DescriptorSerializer {
|
||||
|
||||
private final Interner<TypeParameterDescriptor> typeParameters;
|
||||
private final SerializerExtension extension;
|
||||
private final MutableTypeTable typeTable;
|
||||
private final boolean serializeTypeTableToFunction;
|
||||
|
||||
private DescriptorSerializer(Interner<TypeParameterDescriptor> typeParameters, SerializerExtension extension) {
|
||||
private DescriptorSerializer(
|
||||
@NotNull Interner<TypeParameterDescriptor> typeParameters,
|
||||
@NotNull SerializerExtension extension,
|
||||
@NotNull MutableTypeTable typeTable,
|
||||
boolean serializeTypeTableToFunction
|
||||
) {
|
||||
this.typeParameters = typeParameters;
|
||||
this.extension = extension;
|
||||
this.typeTable = typeTable;
|
||||
this.serializeTypeTableToFunction = serializeTypeTableToFunction;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -63,7 +71,12 @@ public class DescriptorSerializer {
|
||||
|
||||
@NotNull
|
||||
public static DescriptorSerializer createTopLevel(@NotNull SerializerExtension extension) {
|
||||
return new DescriptorSerializer(new Interner<TypeParameterDescriptor>(), extension);
|
||||
return new DescriptorSerializer(new Interner<TypeParameterDescriptor>(), extension, new MutableTypeTable(), false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static DescriptorSerializer createForLambda(@NotNull SerializerExtension extension) {
|
||||
return new DescriptorSerializer(new Interner<TypeParameterDescriptor>(), extension, new MutableTypeTable(), true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -77,7 +90,12 @@ public class DescriptorSerializer {
|
||||
// Calculate type parameter ids for the outer class beforehand, as it would've had happened if we were always
|
||||
// serializing outer classes before nested classes.
|
||||
// Otherwise our interner can get wrong ids because we may serialize classes in any order.
|
||||
DescriptorSerializer serializer = parentSerializer.createChildSerializer();
|
||||
DescriptorSerializer serializer = new DescriptorSerializer(
|
||||
new Interner<TypeParameterDescriptor>(parentSerializer.typeParameters),
|
||||
parentSerializer.extension,
|
||||
new MutableTypeTable(),
|
||||
false
|
||||
);
|
||||
for (TypeParameterDescriptor typeParameter : descriptor.getTypeConstructor().getParameters()) {
|
||||
serializer.typeParameters.intern(typeParameter);
|
||||
}
|
||||
@@ -86,7 +104,7 @@ public class DescriptorSerializer {
|
||||
|
||||
@NotNull
|
||||
private DescriptorSerializer createChildSerializer() {
|
||||
return new DescriptorSerializer(new Interner<TypeParameterDescriptor>(typeParameters), extension);
|
||||
return new DescriptorSerializer(new Interner<TypeParameterDescriptor>(typeParameters), extension, typeTable, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -94,6 +112,10 @@ public class DescriptorSerializer {
|
||||
return extension.getStringTable();
|
||||
}
|
||||
|
||||
private boolean useTypeTable() {
|
||||
return extension.shouldUseTypeTable();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ProtoBuf.Class.Builder classProto(@NotNull ClassDescriptor classDescriptor) {
|
||||
ProtoBuf.Class.Builder builder = ProtoBuf.Class.newBuilder();
|
||||
@@ -113,7 +135,12 @@ public class DescriptorSerializer {
|
||||
if (!KotlinBuiltIns.isSpecialClassWithNoSupertypes(classDescriptor)) {
|
||||
// Special classes (Any, Nothing) have no supertypes
|
||||
for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
|
||||
builder.addSupertype(type(supertype));
|
||||
if (useTypeTable()) {
|
||||
builder.addSupertypeId(typeId(supertype));
|
||||
}
|
||||
else {
|
||||
builder.addSupertype(type(supertype));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,6 +177,11 @@ public class DescriptorSerializer {
|
||||
builder.setCompanionObjectName(getSimpleNameIndex(companionObjectDescriptor.getName()));
|
||||
}
|
||||
|
||||
ProtoBuf.TypeTable typeTableProto = typeTable.serialize();
|
||||
if (typeTableProto != null) {
|
||||
builder.setTypeTable(typeTableProto);
|
||||
}
|
||||
|
||||
extension.serializeClass(classDescriptor, builder);
|
||||
|
||||
return builder;
|
||||
@@ -212,7 +244,12 @@ public class DescriptorSerializer {
|
||||
|
||||
builder.setName(getSimpleNameIndex(descriptor.getName()));
|
||||
|
||||
builder.setReturnType(local.type(descriptor.getType()));
|
||||
if (useTypeTable()) {
|
||||
builder.setReturnTypeId(local.typeId(descriptor.getType()));
|
||||
}
|
||||
else {
|
||||
builder.setReturnType(local.type(descriptor.getType()));
|
||||
}
|
||||
|
||||
for (TypeParameterDescriptor typeParameterDescriptor : descriptor.getTypeParameters()) {
|
||||
builder.addTypeParameter(local.typeParameter(typeParameterDescriptor));
|
||||
@@ -220,7 +257,12 @@ public class DescriptorSerializer {
|
||||
|
||||
ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
|
||||
if (receiverParameter != null) {
|
||||
builder.setReceiverType(local.type(receiverParameter.getType()));
|
||||
if (useTypeTable()) {
|
||||
builder.setReceiverTypeId(local.typeId(receiverParameter.getType()));
|
||||
}
|
||||
else {
|
||||
builder.setReceiverType(local.type(receiverParameter.getType()));
|
||||
}
|
||||
}
|
||||
|
||||
extension.serializeProperty(descriptor, builder);
|
||||
@@ -244,8 +286,14 @@ public class DescriptorSerializer {
|
||||
|
||||
builder.setName(getSimpleNameIndex(descriptor.getName()));
|
||||
|
||||
//noinspection ConstantConditions
|
||||
builder.setReturnType(local.type(descriptor.getReturnType()));
|
||||
if (useTypeTable()) {
|
||||
//noinspection ConstantConditions
|
||||
builder.setReturnTypeId(local.typeId(descriptor.getReturnType()));
|
||||
}
|
||||
else {
|
||||
//noinspection ConstantConditions
|
||||
builder.setReturnType(local.type(descriptor.getReturnType()));
|
||||
}
|
||||
|
||||
for (TypeParameterDescriptor typeParameterDescriptor : descriptor.getTypeParameters()) {
|
||||
builder.addTypeParameter(local.typeParameter(typeParameterDescriptor));
|
||||
@@ -253,13 +301,25 @@ public class DescriptorSerializer {
|
||||
|
||||
ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
|
||||
if (receiverParameter != null) {
|
||||
builder.setReceiverType(local.type(receiverParameter.getType()));
|
||||
if (useTypeTable()) {
|
||||
builder.setReceiverTypeId(local.typeId(receiverParameter.getType()));
|
||||
}
|
||||
else {
|
||||
builder.setReceiverType(local.type(receiverParameter.getType()));
|
||||
}
|
||||
}
|
||||
|
||||
for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getValueParameters()) {
|
||||
builder.addValueParameter(local.valueParameter(valueParameterDescriptor));
|
||||
}
|
||||
|
||||
if (serializeTypeTableToFunction) {
|
||||
ProtoBuf.TypeTable typeTableProto = typeTable.serialize();
|
||||
if (typeTableProto != null) {
|
||||
builder.setTypeTable(typeTableProto);
|
||||
}
|
||||
}
|
||||
|
||||
extension.serializeFunction(descriptor, builder);
|
||||
|
||||
return builder;
|
||||
@@ -305,11 +365,21 @@ public class DescriptorSerializer {
|
||||
|
||||
builder.setName(getSimpleNameIndex(descriptor.getName()));
|
||||
|
||||
builder.setType(type(descriptor.getType()));
|
||||
if (useTypeTable()) {
|
||||
builder.setTypeId(typeId(descriptor.getType()));
|
||||
}
|
||||
else {
|
||||
builder.setType(type(descriptor.getType()));
|
||||
}
|
||||
|
||||
JetType varargElementType = descriptor.getVarargElementType();
|
||||
if (varargElementType != null) {
|
||||
builder.setVarargElementType(type(varargElementType));
|
||||
if (useTypeTable()) {
|
||||
builder.setVarargElementTypeId(typeId(varargElementType));
|
||||
}
|
||||
else {
|
||||
builder.setVarargElementType(type(varargElementType));
|
||||
}
|
||||
}
|
||||
|
||||
extension.serializeValueParameter(descriptor, builder);
|
||||
@@ -337,7 +407,12 @@ public class DescriptorSerializer {
|
||||
if (upperBounds.size() == 1 && KotlinBuiltIns.isDefaultBound(CollectionsKt.single(upperBounds))) return builder;
|
||||
|
||||
for (JetType upperBound : upperBounds) {
|
||||
builder.addUpperBound(type(upperBound));
|
||||
if (useTypeTable()) {
|
||||
builder.addUpperBoundId(typeId(upperBound));
|
||||
}
|
||||
else {
|
||||
builder.addUpperBound(type(upperBound));
|
||||
}
|
||||
}
|
||||
|
||||
return builder;
|
||||
@@ -355,16 +430,26 @@ public class DescriptorSerializer {
|
||||
throw new IllegalStateException("Unknown variance: " + variance);
|
||||
}
|
||||
|
||||
private int typeId(@NotNull JetType type) {
|
||||
return typeTable.get(type(type));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ProtoBuf.Type.Builder type(@NotNull JetType type) {
|
||||
private ProtoBuf.Type.Builder type(@NotNull JetType type) {
|
||||
assert !type.isError() : "Can't serialize error types: " + type; // TODO
|
||||
|
||||
if (FlexibleTypesKt.isFlexible(type)) {
|
||||
Flexibility flexibility = FlexibleTypesKt.flexibility(type);
|
||||
|
||||
return type(flexibility.getLowerBound())
|
||||
.setFlexibleTypeCapabilitiesId(getStringTable().getStringIndex(flexibility.getExtraCapabilities().getId()))
|
||||
.setFlexibleUpperBound(type(flexibility.getUpperBound()));
|
||||
ProtoBuf.Type.Builder lowerBound = type(flexibility.getLowerBound());
|
||||
lowerBound.setFlexibleTypeCapabilitiesId(getStringTable().getStringIndex(flexibility.getExtraCapabilities().getId()));
|
||||
if (useTypeTable()) {
|
||||
lowerBound.setFlexibleUpperBoundId(typeId(flexibility.getUpperBound()));
|
||||
}
|
||||
else {
|
||||
lowerBound.setFlexibleUpperBound(type(flexibility.getUpperBound()));
|
||||
}
|
||||
return lowerBound;
|
||||
}
|
||||
|
||||
ProtoBuf.Type.Builder builder = ProtoBuf.Type.newBuilder();
|
||||
@@ -403,7 +488,13 @@ public class DescriptorSerializer {
|
||||
if (projection != builder.getProjection()) {
|
||||
builder.setProjection(projection);
|
||||
}
|
||||
builder.setType(type(typeProjection.getType()));
|
||||
|
||||
if (useTypeTable()) {
|
||||
builder.setTypeId(typeId(typeProjection.getType()));
|
||||
}
|
||||
else {
|
||||
builder.setType(type(typeProjection.getType()));
|
||||
}
|
||||
}
|
||||
|
||||
return builder;
|
||||
@@ -443,6 +534,11 @@ public class DescriptorSerializer {
|
||||
}
|
||||
}
|
||||
|
||||
ProtoBuf.TypeTable typeTableProto = typeTable.serialize();
|
||||
if (typeTableProto != null) {
|
||||
builder.setTypeTable(typeTableProto);
|
||||
}
|
||||
|
||||
extension.serializePackage(fragments, builder);
|
||||
|
||||
return builder;
|
||||
@@ -461,6 +557,11 @@ public class DescriptorSerializer {
|
||||
}
|
||||
}
|
||||
|
||||
ProtoBuf.TypeTable typeTableProto = typeTable.serialize();
|
||||
if (typeTableProto != null) {
|
||||
builder.setTypeTable(typeTableProto);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.serialization
|
||||
|
||||
import org.jetbrains.kotlin.utils.Interner
|
||||
import java.util.*
|
||||
|
||||
class MutableTypeTable {
|
||||
class TypeWrapper(val type: ProtoBuf.Type.Builder) {
|
||||
// If you'll try to optimize it using structured equals/hashCode, pay attention to extensions present in Type messages
|
||||
private val bytes: ByteArray = type.build().toByteArray()
|
||||
private val hashCode: Int = Arrays.hashCode(bytes)
|
||||
|
||||
override fun hashCode() = hashCode
|
||||
|
||||
override fun equals(other: Any?) = other is TypeWrapper && Arrays.equals(bytes, other.bytes)
|
||||
}
|
||||
|
||||
val interner = Interner<TypeWrapper>()
|
||||
|
||||
operator fun get(type: ProtoBuf.Type.Builder): Int =
|
||||
interner.intern(TypeWrapper(type))
|
||||
|
||||
fun serialize(): ProtoBuf.TypeTable? =
|
||||
if (interner.isEmpty) null
|
||||
else ProtoBuf.TypeTable.newBuilder().apply {
|
||||
for (type in interner.allInternedObjects) {
|
||||
addType(type.type)
|
||||
}
|
||||
}.build()
|
||||
}
|
||||
@@ -26,6 +26,10 @@ public abstract class SerializerExtension {
|
||||
@NotNull
|
||||
public abstract StringTable getStringTable();
|
||||
|
||||
public boolean shouldUseTypeTable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void serializeClass(@NotNull ClassDescriptor descriptor, @NotNull ProtoBuf.Class.Builder proto) {
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user