Use type table in DescriptorSerializer, add switch to enable/disable, test

This commit is contained in:
Alexander Udalov
2015-10-09 03:59:27 +03:00
parent 82d2e623d3
commit fb5d8de84b
25 changed files with 3360 additions and 53 deletions
@@ -222,7 +222,9 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
writeKotlinSyntheticClassAnnotation(v, state); writeKotlinSyntheticClassAnnotation(v, state);
DescriptorSerializer serializer = DescriptorSerializer serializer =
DescriptorSerializer.createTopLevel(new JvmSerializerExtension(v.getSerializationBindings(), typeMapper)); DescriptorSerializer.createForLambda(
new JvmSerializerExtension(v.getSerializationBindings(), typeMapper, state.getUseTypeTableInSerializer())
);
ProtoBuf.Function functionProto = serializer.functionProto(funDescriptor).build(); ProtoBuf.Function functionProto = serializer.functionProto(funDescriptor).build();
@@ -256,7 +256,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
DescriptorSerializer serializer = DescriptorSerializer serializer =
DescriptorSerializer.create(descriptor, new JvmSerializerExtension(v.getSerializationBindings(), typeMapper)); DescriptorSerializer.create(descriptor, new JvmSerializerExtension(
v.getSerializationBindings(), typeMapper, state.getUseTypeTableInSerializer()
));
ProtoBuf.Class classProto = serializer.classProto(descriptor).build(); ProtoBuf.Class classProto = serializer.classProto(descriptor).build();
@@ -85,7 +85,9 @@ public class MultifileClassPartCodegen(
val bindings = v.serializationBindings val bindings = v.serializationBindings
val serializer = DescriptorSerializer.createTopLevel(JvmSerializerExtension(bindings, state.typeMapper)) val serializer = DescriptorSerializer.createTopLevel(
JvmSerializerExtension(bindings, state.typeMapper, state.useTypeTableInSerializer)
)
val packageProto = serializer.packagePartProto(members).build() val packageProto = serializer.packagePartProto(members).build()
val av = v.newAnnotation(AsmUtil.asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_MULTIFILE_CLASS_PART), true) val av = v.newAnnotation(AsmUtil.asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_MULTIFILE_CLASS_PART), true)
@@ -270,7 +270,9 @@ public class PackageCodegen {
if (file.isScript()) return; if (file.isScript()) return;
} }
DescriptorSerializer serializer = DescriptorSerializer.createTopLevel(new JvmSerializerExtension(bindings, state.getTypeMapper())); DescriptorSerializer serializer = DescriptorSerializer.createTopLevel(new JvmSerializerExtension(
bindings, state.getTypeMapper(), state.getUseTypeTableInSerializer()
));
Collection<PackageFragmentDescriptor> packageFragments = Lists.newArrayList(); Collection<PackageFragmentDescriptor> packageFragments = Lists.newArrayList();
ContainerUtil.addIfNotNull(packageFragments, packageFragment); ContainerUtil.addIfNotNull(packageFragments, packageFragment);
ContainerUtil.addIfNotNull(packageFragments, compiledPackageFragment); ContainerUtil.addIfNotNull(packageFragments, compiledPackageFragment);
@@ -121,7 +121,9 @@ public class PackagePartCodegen extends MemberCodegen<JetFile> {
JvmSerializationBindings bindings = v.getSerializationBindings(); JvmSerializationBindings bindings = v.getSerializationBindings();
DescriptorSerializer serializer = DescriptorSerializer.createTopLevel(new JvmSerializerExtension(bindings, state.getTypeMapper())); DescriptorSerializer serializer = DescriptorSerializer.createTopLevel(new JvmSerializerExtension(
bindings, state.getTypeMapper(), state.getUseTypeTableInSerializer()
));
ProtoBuf.Package packageProto = serializer.packagePartProto(members).build(); ProtoBuf.Package packageProto = serializer.packagePartProto(members).build();
AnnotationVisitor av = v.newAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_FILE_FACADE), true); AnnotationVisitor av = v.newAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_FILE_FACADE), true);
@@ -42,11 +42,13 @@ public class JvmSerializerExtension extends SerializerExtension {
private final JvmSerializationBindings bindings; private final JvmSerializationBindings bindings;
private final StringTable stringTable; private final StringTable stringTable;
private final AnnotationSerializer annotationSerializer; private final AnnotationSerializer annotationSerializer;
private final boolean useTypeTable;
public JvmSerializerExtension(@NotNull JvmSerializationBindings bindings, @NotNull JetTypeMapper typeMapper) { public JvmSerializerExtension(@NotNull JvmSerializationBindings bindings, @NotNull JetTypeMapper typeMapper, boolean useTypeTable) {
this.bindings = bindings; this.bindings = bindings;
this.stringTable = new JvmStringTable(typeMapper); this.stringTable = new JvmStringTable(typeMapper);
this.annotationSerializer = new AnnotationSerializer(stringTable); this.annotationSerializer = new AnnotationSerializer(stringTable);
this.useTypeTable = useTypeTable;
} }
@NotNull @NotNull
@@ -55,6 +57,11 @@ public class JvmSerializerExtension extends SerializerExtension {
return stringTable; return stringTable;
} }
@Override
public boolean shouldUseTypeTable() {
return useTypeTable;
}
@Override @Override
public void serializeClass(@NotNull ClassDescriptor descriptor, @NotNull ProtoBuf.Class.Builder proto) { public void serializeClass(@NotNull ClassDescriptor descriptor, @NotNull ProtoBuf.Class.Builder proto) {
AnnotationDescriptor annotation = descriptor.getAnnotations().findAnnotation(KotlinBuiltIns.FQ_NAMES.annotation); AnnotationDescriptor annotation = descriptor.getAnnotations().findAnnotation(KotlinBuiltIns.FQ_NAMES.annotation);
@@ -52,6 +52,7 @@ public class GenerationState @JvmOverloads constructor(
public val generateDeclaredClassFilter: GenerationState.GenerateClassFilter = GenerationState.GenerateClassFilter.GENERATE_ALL, public val generateDeclaredClassFilter: GenerationState.GenerateClassFilter = GenerationState.GenerateClassFilter.GENERATE_ALL,
disableInline: Boolean = false, disableInline: Boolean = false,
disableOptimization: Boolean = false, disableOptimization: Boolean = false,
public val useTypeTableInSerializer: Boolean = false,
public val packageFacadesAsMultifileClasses: Boolean = false, public val packageFacadesAsMultifileClasses: Boolean = false,
public val diagnostics: DiagnosticSink = DiagnosticSink.DO_NOTHING, public val diagnostics: DiagnosticSink = DiagnosticSink.DO_NOTHING,
public val packagesWithObsoleteParts: Collection<FqName> = emptySet(), public val packagesWithObsoleteParts: Collection<FqName> = emptySet(),
@@ -105,7 +105,7 @@ public class BuiltInsSerializer(private val dependOnOldBuiltIns: Boolean) {
System.err.println("Could not make directories: " + destDir) System.err.println("Could not make directories: " + destDir)
} }
files.map { it.getPackageFqName() }.toSet().forEach { files.map { it.packageFqName }.toSet().forEach {
fqName -> fqName ->
serializePackage(moduleDescriptor, fqName, destDir) serializePackage(moduleDescriptor, fqName, destDir)
} }
@@ -117,11 +117,10 @@ public class BuiltInsSerializer(private val dependOnOldBuiltIns: Boolean) {
// TODO: perform some kind of validation? At the moment not possible because DescriptorValidator is in compiler-tests // TODO: perform some kind of validation? At the moment not possible because DescriptorValidator is in compiler-tests
// DescriptorValidator.validate(packageView) // DescriptorValidator.validate(packageView)
val serializer = DescriptorSerializer.createTopLevel(BuiltInsSerializerExtension())
val classifierDescriptors = DescriptorSerializer.sort(packageView.memberScope.getDescriptors(DescriptorKindFilter.CLASSIFIERS)) val classifierDescriptors = DescriptorSerializer.sort(packageView.memberScope.getDescriptors(DescriptorKindFilter.CLASSIFIERS))
serializeClasses(classifierDescriptors, serializer) { val extension = BuiltInsSerializerExtension()
serializeClasses(classifierDescriptors, extension) {
classDescriptor, classProto -> classDescriptor, classProto ->
val stream = ByteArrayOutputStream() val stream = ByteArrayOutputStream()
classProto.writeTo(stream) classProto.writeTo(stream)
@@ -130,13 +129,13 @@ public class BuiltInsSerializer(private val dependOnOldBuiltIns: Boolean) {
val packageStream = ByteArrayOutputStream() val packageStream = ByteArrayOutputStream()
val fragments = packageView.fragments val fragments = packageView.fragments
val packageProto = serializer.packageProto(fragments).build() ?: error("Package fragments not serialized: $fragments") val packageProto = DescriptorSerializer.createTopLevel(extension).packageProto(fragments).build()
packageProto.writeTo(packageStream) packageProto.writeTo(packageStream)
write(destDir, BuiltInsSerializedResourcePaths.getPackageFilePath(fqName), packageStream, write(destDir, BuiltInsSerializedResourcePaths.getPackageFilePath(fqName), packageStream,
BuiltInsSerializedResourcePaths.fallbackPaths.getPackageFilePath(fqName)) BuiltInsSerializedResourcePaths.fallbackPaths.getPackageFilePath(fqName))
val nameStream = ByteArrayOutputStream() val nameStream = ByteArrayOutputStream()
serializer.stringTable.serializeTo(nameStream) extension.stringTable.serializeTo(nameStream)
write(destDir, BuiltInsSerializedResourcePaths.getStringTableFilePath(fqName), nameStream, write(destDir, BuiltInsSerializedResourcePaths.getStringTableFilePath(fqName), nameStream,
BuiltInsSerializedResourcePaths.fallbackPaths.getStringTableFilePath(fqName)) BuiltInsSerializedResourcePaths.fallbackPaths.getStringTableFilePath(fqName))
} }
@@ -144,7 +143,7 @@ public class BuiltInsSerializer(private val dependOnOldBuiltIns: Boolean) {
private fun write(destDir: File, fileName: String, stream: ByteArrayOutputStream, legacyFileName: String? = null) { private fun write(destDir: File, fileName: String, stream: ByteArrayOutputStream, legacyFileName: String? = null) {
totalSize += stream.size() totalSize += stream.size()
totalFiles++ totalFiles++
File(destDir, fileName).getParentFile().mkdirs() File(destDir, fileName).parentFile.mkdirs()
File(destDir, fileName).writeBytes(stream.toByteArray()) File(destDir, fileName).writeBytes(stream.toByteArray())
legacyFileName?.let { fileName -> legacyFileName?.let { fileName ->
@@ -154,18 +153,18 @@ public class BuiltInsSerializer(private val dependOnOldBuiltIns: Boolean) {
private fun serializeClass( private fun serializeClass(
classDescriptor: ClassDescriptor, classDescriptor: ClassDescriptor,
serializer: DescriptorSerializer, serializer: BuiltInsSerializerExtension,
writeClass: (ClassDescriptor, ProtoBuf.Class) -> Unit writeClass: (ClassDescriptor, ProtoBuf.Class) -> Unit
) { ) {
val classProto = serializer.classProto(classDescriptor).build() ?: error("Class not serialized: $classDescriptor") val classProto = DescriptorSerializer.createTopLevel(serializer).classProto(classDescriptor).build()
writeClass(classDescriptor, classProto) writeClass(classDescriptor, classProto)
serializeClasses(classDescriptor.getUnsubstitutedInnerClassesScope().getDescriptors(), serializer, writeClass) serializeClasses(classDescriptor.unsubstitutedInnerClassesScope.getDescriptors(), serializer, writeClass)
} }
private fun serializeClasses( private fun serializeClasses(
descriptors: Collection<DeclarationDescriptor>, descriptors: Collection<DeclarationDescriptor>,
serializer: DescriptorSerializer, serializer: BuiltInsSerializerExtension,
writeClass: (ClassDescriptor, ProtoBuf.Class) -> Unit writeClass: (ClassDescriptor, ProtoBuf.Class) -> Unit
) { ) {
for (descriptor in descriptors) { for (descriptor in descriptors) {
@@ -28,6 +28,8 @@ public class BuiltInsSerializerExtension : SerializerExtension() {
override fun getStringTable(): StringTable = stringTable override fun getStringTable(): StringTable = stringTable
override fun shouldUseTypeTable(): Boolean = true
override fun serializeClass(descriptor: ClassDescriptor, proto: ProtoBuf.Class.Builder) { override fun serializeClass(descriptor: ClassDescriptor, proto: ProtoBuf.Class.Builder) {
for (annotation in descriptor.annotations) { for (annotation in descriptor.annotations) {
proto.addExtension(BuiltInsProtoBuf.classAnnotation, annotationSerializer.serializeAnnotation(annotation)) proto.addExtension(BuiltInsProtoBuf.classAnnotation, annotationSerializer.serializeAnnotation(annotation))
@@ -398,6 +398,7 @@ public class KotlinToJVMBytecodeCompiler {
GenerationState.GenerateClassFilter.GENERATE_ALL, GenerationState.GenerateClassFilter.GENERATE_ALL,
configuration.get(JVMConfigurationKeys.DISABLE_INLINE, false), configuration.get(JVMConfigurationKeys.DISABLE_INLINE, false),
configuration.get(JVMConfigurationKeys.DISABLE_OPTIMIZATION, false), configuration.get(JVMConfigurationKeys.DISABLE_OPTIMIZATION, false),
/* useTypeTableInSerializer = */ false,
configuration.get(JVMConfigurationKeys.PACKAGE_FACADES_AS_MULTIFILE_CLASSES, false), configuration.get(JVMConfigurationKeys.PACKAGE_FACADES_AS_MULTIFILE_CLASSES, false),
diagnosticHolder, diagnosticHolder,
packagesWithObsoleteParts, packagesWithObsoleteParts,
@@ -429,6 +429,7 @@ public class KotlinJavaFileStubProvider<T extends WithFileStubAndExtraDiagnostic
/*generateClassFilter=*/stubGenerationStrategy.getGenerateClassFilter(), /*generateClassFilter=*/stubGenerationStrategy.getGenerateClassFilter(),
/*disableInline=*/false, /*disableInline=*/false,
/*disableOptimization=*/false, /*disableOptimization=*/false,
/*useTypeTableInSerializer=*/false,
/*packageFacadesAsMultifileClasses=*/false, /*packageFacadesAsMultifileClasses=*/false,
forExtraDiagnostics forExtraDiagnostics
); );
@@ -39,13 +39,21 @@ import java.util.*;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry; import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry;
public class DescriptorSerializer { public class DescriptorSerializer {
private final Interner<TypeParameterDescriptor> typeParameters; private final Interner<TypeParameterDescriptor> typeParameters;
private final SerializerExtension extension; 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.typeParameters = typeParameters;
this.extension = extension; this.extension = extension;
this.typeTable = typeTable;
this.serializeTypeTableToFunction = serializeTypeTableToFunction;
} }
@NotNull @NotNull
@@ -63,7 +71,12 @@ public class DescriptorSerializer {
@NotNull @NotNull
public static DescriptorSerializer createTopLevel(@NotNull SerializerExtension extension) { 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 @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 // 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. // serializing outer classes before nested classes.
// Otherwise our interner can get wrong ids because we may serialize classes in any order. // 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()) { for (TypeParameterDescriptor typeParameter : descriptor.getTypeConstructor().getParameters()) {
serializer.typeParameters.intern(typeParameter); serializer.typeParameters.intern(typeParameter);
} }
@@ -86,7 +104,7 @@ public class DescriptorSerializer {
@NotNull @NotNull
private DescriptorSerializer createChildSerializer() { private DescriptorSerializer createChildSerializer() {
return new DescriptorSerializer(new Interner<TypeParameterDescriptor>(typeParameters), extension); return new DescriptorSerializer(new Interner<TypeParameterDescriptor>(typeParameters), extension, typeTable, false);
} }
@NotNull @NotNull
@@ -94,6 +112,10 @@ public class DescriptorSerializer {
return extension.getStringTable(); return extension.getStringTable();
} }
private boolean useTypeTable() {
return extension.shouldUseTypeTable();
}
@NotNull @NotNull
public ProtoBuf.Class.Builder classProto(@NotNull ClassDescriptor classDescriptor) { public ProtoBuf.Class.Builder classProto(@NotNull ClassDescriptor classDescriptor) {
ProtoBuf.Class.Builder builder = ProtoBuf.Class.newBuilder(); ProtoBuf.Class.Builder builder = ProtoBuf.Class.newBuilder();
@@ -113,7 +135,12 @@ public class DescriptorSerializer {
if (!KotlinBuiltIns.isSpecialClassWithNoSupertypes(classDescriptor)) { if (!KotlinBuiltIns.isSpecialClassWithNoSupertypes(classDescriptor)) {
// Special classes (Any, Nothing) have no supertypes // Special classes (Any, Nothing) have no supertypes
for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) { 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())); builder.setCompanionObjectName(getSimpleNameIndex(companionObjectDescriptor.getName()));
} }
ProtoBuf.TypeTable typeTableProto = typeTable.serialize();
if (typeTableProto != null) {
builder.setTypeTable(typeTableProto);
}
extension.serializeClass(classDescriptor, builder); extension.serializeClass(classDescriptor, builder);
return builder; return builder;
@@ -212,7 +244,12 @@ public class DescriptorSerializer {
builder.setName(getSimpleNameIndex(descriptor.getName())); 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()) { for (TypeParameterDescriptor typeParameterDescriptor : descriptor.getTypeParameters()) {
builder.addTypeParameter(local.typeParameter(typeParameterDescriptor)); builder.addTypeParameter(local.typeParameter(typeParameterDescriptor));
@@ -220,7 +257,12 @@ public class DescriptorSerializer {
ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter(); ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
if (receiverParameter != null) { 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); extension.serializeProperty(descriptor, builder);
@@ -244,8 +286,14 @@ public class DescriptorSerializer {
builder.setName(getSimpleNameIndex(descriptor.getName())); builder.setName(getSimpleNameIndex(descriptor.getName()));
//noinspection ConstantConditions if (useTypeTable()) {
builder.setReturnType(local.type(descriptor.getReturnType())); //noinspection ConstantConditions
builder.setReturnTypeId(local.typeId(descriptor.getReturnType()));
}
else {
//noinspection ConstantConditions
builder.setReturnType(local.type(descriptor.getReturnType()));
}
for (TypeParameterDescriptor typeParameterDescriptor : descriptor.getTypeParameters()) { for (TypeParameterDescriptor typeParameterDescriptor : descriptor.getTypeParameters()) {
builder.addTypeParameter(local.typeParameter(typeParameterDescriptor)); builder.addTypeParameter(local.typeParameter(typeParameterDescriptor));
@@ -253,13 +301,25 @@ public class DescriptorSerializer {
ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter(); ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
if (receiverParameter != null) { 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()) { for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getValueParameters()) {
builder.addValueParameter(local.valueParameter(valueParameterDescriptor)); builder.addValueParameter(local.valueParameter(valueParameterDescriptor));
} }
if (serializeTypeTableToFunction) {
ProtoBuf.TypeTable typeTableProto = typeTable.serialize();
if (typeTableProto != null) {
builder.setTypeTable(typeTableProto);
}
}
extension.serializeFunction(descriptor, builder); extension.serializeFunction(descriptor, builder);
return builder; return builder;
@@ -305,11 +365,21 @@ public class DescriptorSerializer {
builder.setName(getSimpleNameIndex(descriptor.getName())); 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(); JetType varargElementType = descriptor.getVarargElementType();
if (varargElementType != null) { if (varargElementType != null) {
builder.setVarargElementType(type(varargElementType)); if (useTypeTable()) {
builder.setVarargElementTypeId(typeId(varargElementType));
}
else {
builder.setVarargElementType(type(varargElementType));
}
} }
extension.serializeValueParameter(descriptor, builder); extension.serializeValueParameter(descriptor, builder);
@@ -337,7 +407,12 @@ public class DescriptorSerializer {
if (upperBounds.size() == 1 && KotlinBuiltIns.isDefaultBound(CollectionsKt.single(upperBounds))) return builder; if (upperBounds.size() == 1 && KotlinBuiltIns.isDefaultBound(CollectionsKt.single(upperBounds))) return builder;
for (JetType upperBound : upperBounds) { for (JetType upperBound : upperBounds) {
builder.addUpperBound(type(upperBound)); if (useTypeTable()) {
builder.addUpperBoundId(typeId(upperBound));
}
else {
builder.addUpperBound(type(upperBound));
}
} }
return builder; return builder;
@@ -355,16 +430,26 @@ public class DescriptorSerializer {
throw new IllegalStateException("Unknown variance: " + variance); throw new IllegalStateException("Unknown variance: " + variance);
} }
private int typeId(@NotNull JetType type) {
return typeTable.get(type(type));
}
@NotNull @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 assert !type.isError() : "Can't serialize error types: " + type; // TODO
if (FlexibleTypesKt.isFlexible(type)) { if (FlexibleTypesKt.isFlexible(type)) {
Flexibility flexibility = FlexibleTypesKt.flexibility(type); Flexibility flexibility = FlexibleTypesKt.flexibility(type);
return type(flexibility.getLowerBound()) ProtoBuf.Type.Builder lowerBound = type(flexibility.getLowerBound());
.setFlexibleTypeCapabilitiesId(getStringTable().getStringIndex(flexibility.getExtraCapabilities().getId())) lowerBound.setFlexibleTypeCapabilitiesId(getStringTable().getStringIndex(flexibility.getExtraCapabilities().getId()));
.setFlexibleUpperBound(type(flexibility.getUpperBound())); if (useTypeTable()) {
lowerBound.setFlexibleUpperBoundId(typeId(flexibility.getUpperBound()));
}
else {
lowerBound.setFlexibleUpperBound(type(flexibility.getUpperBound()));
}
return lowerBound;
} }
ProtoBuf.Type.Builder builder = ProtoBuf.Type.newBuilder(); ProtoBuf.Type.Builder builder = ProtoBuf.Type.newBuilder();
@@ -403,7 +488,13 @@ public class DescriptorSerializer {
if (projection != builder.getProjection()) { if (projection != builder.getProjection()) {
builder.setProjection(projection); builder.setProjection(projection);
} }
builder.setType(type(typeProjection.getType()));
if (useTypeTable()) {
builder.setTypeId(typeId(typeProjection.getType()));
}
else {
builder.setType(type(typeProjection.getType()));
}
} }
return builder; return builder;
@@ -443,6 +534,11 @@ public class DescriptorSerializer {
} }
} }
ProtoBuf.TypeTable typeTableProto = typeTable.serialize();
if (typeTableProto != null) {
builder.setTypeTable(typeTableProto);
}
extension.serializePackage(fragments, builder); extension.serializePackage(fragments, builder);
return builder; return builder;
@@ -461,6 +557,11 @@ public class DescriptorSerializer {
} }
} }
ProtoBuf.TypeTable typeTableProto = typeTable.serialize();
if (typeTableProto != null) {
builder.setTypeTable(typeTableProto);
}
return builder; 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 @NotNull
public abstract StringTable getStringTable(); public abstract StringTable getStringTable();
public boolean shouldUseTypeTable() {
return false;
}
public void serializeClass(@NotNull ClassDescriptor descriptor, @NotNull ProtoBuf.Class.Builder proto) { public void serializeClass(@NotNull ClassDescriptor descriptor, @NotNull ProtoBuf.Class.Builder proto) {
} }
@@ -22,6 +22,7 @@ import kotlin.StringsKt;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.analyzer.AnalysisResult; import org.jetbrains.kotlin.analyzer.AnalysisResult;
import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider;
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment; import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment;
import org.jetbrains.kotlin.cli.jvm.config.JVMConfigurationKeys; import org.jetbrains.kotlin.cli.jvm.config.JVMConfigurationKeys;
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime; import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime;
@@ -29,7 +30,6 @@ import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.config.CompilerConfiguration; import org.jetbrains.kotlin.config.CompilerConfiguration;
import org.jetbrains.kotlin.resolve.AnalyzingUtils; import org.jetbrains.kotlin.resolve.AnalyzingUtils;
import org.jetbrains.kotlin.resolve.BindingTraceContext; import org.jetbrains.kotlin.resolve.BindingTraceContext;
import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider;
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil; import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil;
import org.jetbrains.kotlin.test.JetTestUtils; import org.jetbrains.kotlin.test.JetTestUtils;
import org.jetbrains.kotlin.utils.ExceptionUtilsKt; import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
@@ -67,6 +67,7 @@ public class CodegenTestUtil {
GenerationState.GenerateClassFilter.GENERATE_ALL, GenerationState.GenerateClassFilter.GENERATE_ALL,
configuration.get(JVMConfigurationKeys.DISABLE_INLINE, false), configuration.get(JVMConfigurationKeys.DISABLE_INLINE, false),
configuration.get(JVMConfigurationKeys.DISABLE_OPTIMIZATION, false), configuration.get(JVMConfigurationKeys.DISABLE_OPTIMIZATION, false),
/* useTypeTableInSerializer = */ false,
configuration.get(JVMConfigurationKeys.PACKAGE_FACADES_AS_MULTIFILE_CLASSES, false), configuration.get(JVMConfigurationKeys.PACKAGE_FACADES_AS_MULTIFILE_CLASSES, false),
forExtraDiagnostics forExtraDiagnostics
); );
@@ -49,7 +49,7 @@ public class GenerationUtils {
) { ) {
AnalysisResult analysisResult = AnalysisResult analysisResult =
JvmResolveUtil.analyzeOneFileWithJavaIntegrationAndCheckForErrors(psiFile, new JvmPackagePartProvider(environment)); JvmResolveUtil.analyzeOneFileWithJavaIntegrationAndCheckForErrors(psiFile, new JvmPackagePartProvider(environment));
return compileFilesGetGenerationState(psiFile.getProject(), analysisResult, Collections.singletonList(psiFile)); return compileFilesGetGenerationState(psiFile.getProject(), analysisResult, Collections.singletonList(psiFile), false);
} }
@NotNull @NotNull
@@ -63,14 +63,15 @@ public class GenerationUtils {
) { ) {
AnalysisResult analysisResult = JvmResolveUtil.analyzeFilesWithJavaIntegrationAndCheckForErrors( AnalysisResult analysisResult = JvmResolveUtil.analyzeFilesWithJavaIntegrationAndCheckForErrors(
project, files, packagePartProvider); project, files, packagePartProvider);
return compileFilesGetGenerationState(project, analysisResult, files); return compileFilesGetGenerationState(project, analysisResult, files, false);
} }
@NotNull @NotNull
public static GenerationState compileFilesGetGenerationState( public static GenerationState compileFilesGetGenerationState(
@NotNull Project project, @NotNull Project project,
@NotNull AnalysisResult analysisResult, @NotNull AnalysisResult analysisResult,
@NotNull List<JetFile> files @NotNull List<JetFile> files,
boolean useTypeTableInSerializer
) { ) {
analysisResult.throwIfError(); analysisResult.throwIfError();
GenerationState state = new GenerationState( GenerationState state = new GenerationState(
@@ -78,7 +79,11 @@ public class GenerationUtils {
analysisResult.getModuleDescriptor(), analysisResult.getBindingContext(), analysisResult.getModuleDescriptor(), analysisResult.getBindingContext(),
files, files,
/* disableCallAssertions = */ false, /* disableCallAssertions = */ false,
/* disableParamAssertions = */ false /* disableParamAssertions = */ false,
GenerationState.GenerateClassFilter.GENERATE_ALL,
/* disableInline = */ false,
/* disableOptimization = */ false,
useTypeTableInSerializer
); );
KotlinCodegenFacade.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION); KotlinCodegenFacade.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION);
return state; return state;
@@ -23,6 +23,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.analyzer.AnalysisResult; import org.jetbrains.kotlin.analyzer.AnalysisResult;
import org.jetbrains.kotlin.cli.jvm.compiler.CliLightClassGenerationSupport; import org.jetbrains.kotlin.cli.jvm.compiler.CliLightClassGenerationSupport;
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles; import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles;
import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider;
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment; import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment;
import org.jetbrains.kotlin.cli.jvm.config.JvmContentRootsKt; import org.jetbrains.kotlin.cli.jvm.config.JvmContentRootsKt;
import org.jetbrains.kotlin.cli.jvm.config.ModuleNameKt; import org.jetbrains.kotlin.cli.jvm.config.ModuleNameKt;
@@ -38,7 +39,6 @@ import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.TopDownAnalysisMode; import org.jetbrains.kotlin.resolve.TopDownAnalysisMode;
import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM; import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM;
import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider;
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil; import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil;
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor; import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor;
import org.jetbrains.kotlin.test.ConfigurationKind; import org.jetbrains.kotlin.test.ConfigurationKind;
@@ -78,7 +78,7 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir {
File sourcesDir = new File(expectedFileName.replaceFirst("\\.txt$", "")); File sourcesDir = new File(expectedFileName.replaceFirst("\\.txt$", ""));
List<File> kotlinSources = FileUtil.findFilesByMask(Pattern.compile(".+\\.kt"), sourcesDir); List<File> kotlinSources = FileUtil.findFilesByMask(Pattern.compile(".+\\.kt"), sourcesDir);
compileKotlinToDirAndGetAnalysisResult(kotlinSources, tmpdir, myTestRootDisposable, ConfigurationKind.JDK_ONLY); compileKotlinToDirAndGetAnalysisResult(kotlinSources, tmpdir, myTestRootDisposable, ConfigurationKind.JDK_ONLY, false);
List<File> javaSources = FileUtil.findFilesByMask(Pattern.compile(".+\\.java"), sourcesDir); List<File> javaSources = FileUtil.findFilesByMask(Pattern.compile(".+\\.java"), sourcesDir);
Pair<PackageViewDescriptor, BindingContext> binaryPackageAndContext = compileJavaAndLoadTestPackageAndBindingContextFromBinary( Pair<PackageViewDescriptor, BindingContext> binaryPackageAndContext = compileJavaAndLoadTestPackageAndBindingContextFromBinary(
@@ -93,18 +93,25 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir {
} }
protected void doTestCompiledKotlin(@NotNull String ktFileName) throws Exception { protected void doTestCompiledKotlin(@NotNull String ktFileName) throws Exception {
doTestCompiledKotlin(ktFileName, ConfigurationKind.JDK_ONLY); doTestCompiledKotlin(ktFileName, ConfigurationKind.JDK_ONLY, false);
}
protected void doTestCompiledKotlinWithTypeTable(@NotNull String ktFileName) throws Exception {
doTestCompiledKotlin(ktFileName, ConfigurationKind.JDK_ONLY, true);
} }
protected void doTestCompiledKotlinWithStdlib(@NotNull String ktFileName) throws Exception { protected void doTestCompiledKotlinWithStdlib(@NotNull String ktFileName) throws Exception {
doTestCompiledKotlin(ktFileName, ConfigurationKind.ALL); doTestCompiledKotlin(ktFileName, ConfigurationKind.ALL, false);
} }
protected void doTestCompiledKotlin(@NotNull String ktFileName, @NotNull ConfigurationKind configurationKind) throws Exception { private void doTestCompiledKotlin(
@NotNull String ktFileName, @NotNull ConfigurationKind configurationKind, boolean useTypeTableInSerializer
) throws Exception {
File ktFile = new File(ktFileName); File ktFile = new File(ktFileName);
File txtFile = new File(ktFileName.replaceFirst("\\.kt$", ".txt")); File txtFile = new File(ktFileName.replaceFirst("\\.kt$", ".txt"));
AnalysisResult result = compileKotlinToDirAndGetAnalysisResult(Collections.singletonList(ktFile), tmpdir, getTestRootDisposable(), AnalysisResult result = compileKotlinToDirAndGetAnalysisResult(
configurationKind); Collections.singletonList(ktFile), tmpdir, getTestRootDisposable(), configurationKind, useTypeTableInSerializer
);
PackageViewDescriptor packageFromSource = result.getModuleDescriptor().getPackage(TEST_PACKAGE_FQNAME); PackageViewDescriptor packageFromSource = result.getModuleDescriptor().getPackage(TEST_PACKAGE_FQNAME);
Assert.assertEquals("test", packageFromSource.getName().asString()); Assert.assertEquals("test", packageFromSource.getName().asString());
@@ -0,0 +1,23 @@
/*
* 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.jvm.compiler
abstract class AbstractLoadKotlinWithTypeTableTest : AbstractLoadJavaTest() {
protected fun doTest(fileName: String) {
doTestCompiledKotlinWithTypeTable(fileName)
}
}
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.analyzer.AnalysisResult;
import org.jetbrains.kotlin.cli.common.output.outputUtils.OutputUtilsKt; import org.jetbrains.kotlin.cli.common.output.outputUtils.OutputUtilsKt;
import org.jetbrains.kotlin.cli.jvm.compiler.CliLightClassGenerationSupport; import org.jetbrains.kotlin.cli.jvm.compiler.CliLightClassGenerationSupport;
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles; import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles;
import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider;
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment; import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment;
import org.jetbrains.kotlin.codegen.GenerationUtils; import org.jetbrains.kotlin.codegen.GenerationUtils;
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime; import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime;
@@ -38,7 +39,6 @@ import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.JetFile; import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider;
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil; import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil;
import org.jetbrains.kotlin.resolve.lazy.LazyResolveTestUtil; import org.jetbrains.kotlin.resolve.lazy.LazyResolveTestUtil;
import org.jetbrains.kotlin.test.ConfigurationKind; import org.jetbrains.kotlin.test.ConfigurationKind;
@@ -64,12 +64,15 @@ public final class LoadDescriptorUtil {
@NotNull List<File> kotlinFiles, @NotNull List<File> kotlinFiles,
@NotNull File outDir, @NotNull File outDir,
@NotNull Disposable disposable, @NotNull Disposable disposable,
@NotNull ConfigurationKind configurationKind @NotNull ConfigurationKind configurationKind,
boolean useTypeTableInSerializer
) { ) {
JetFilesAndAnalysisResult filesAndResult = JetFilesAndAnalysisResult.createJetFilesAndAnalyze(kotlinFiles, disposable, configurationKind); JetFilesAndAnalysisResult filesAndResult = JetFilesAndAnalysisResult.createJetFilesAndAnalyze(kotlinFiles, disposable, configurationKind);
AnalysisResult result = filesAndResult.getAnalysisResult(); AnalysisResult result = filesAndResult.getAnalysisResult();
List<JetFile> files = filesAndResult.getJetFiles(); List<JetFile> files = filesAndResult.getJetFiles();
GenerationState state = GenerationUtils.compileFilesGetGenerationState(files.get(0).getProject(), result, files); GenerationState state = GenerationUtils.compileFilesGetGenerationState(
files.get(0).getProject(), result, files, useTypeTableInSerializer
);
OutputUtilsKt.writeAllTo(state.getFactory(), outDir); OutputUtilsKt.writeAllTo(state.getFactory(), outDir);
return result; return result;
} }
@@ -38,7 +38,7 @@ import java.net.URLClassLoader
public abstract class AbstractLocalClassProtoTest : TestCaseWithTmpdir() { public abstract class AbstractLocalClassProtoTest : TestCaseWithTmpdir() {
protected fun doTest(filename: String) { protected fun doTest(filename: String) {
val source = File(filename) val source = File(filename)
LoadDescriptorUtil.compileKotlinToDirAndGetAnalysisResult(listOf(source), tmpdir, testRootDisposable, ConfigurationKind.ALL) LoadDescriptorUtil.compileKotlinToDirAndGetAnalysisResult(listOf(source), tmpdir, testRootDisposable, ConfigurationKind.ALL, false)
val classNameSuffix = InTextDirectivesUtils.findStringWithPrefixes(source.readText(), "// CLASS_NAME_SUFFIX: ") val classNameSuffix = InTextDirectivesUtils.findStringWithPrefixes(source.readText(), "// CLASS_NAME_SUFFIX: ")
?: error("CLASS_NAME_SUFFIX directive not found in test data") ?: error("CLASS_NAME_SUFFIX directive not found in test data")
@@ -521,7 +521,7 @@ public class JetTestUtils {
@Nullable File javaErrorFile @Nullable File javaErrorFile
) throws IOException { ) throws IOException {
if (!ktFiles.isEmpty()) { if (!ktFiles.isEmpty()) {
compileKotlinToDirAndGetAnalysisResult(ktFiles, outDir, disposable, ALL); compileKotlinToDirAndGetAnalysisResult(ktFiles, outDir, disposable, ALL, false);
} }
else { else {
boolean mkdirs = outDir.mkdirs(); boolean mkdirs = outDir.mkdirs();
@@ -68,4 +68,8 @@ public final class Interner<T> {
} }
}); });
} }
public boolean isEmpty() {
return interned.isEmpty() && (parent == null || parent.isEmpty());
}
} }
@@ -260,6 +260,10 @@ fun main(args: Array<String>) {
model("loadJava/sourceJava", extension = "java", testMethod = "doTestSourceJava") model("loadJava/sourceJava", extension = "java", testMethod = "doTestSourceJava")
} }
testClass<AbstractLoadKotlinWithTypeTableTest>() {
model("loadJava/compiledKotlin")
}
testClass<AbstractJvmRuntimeDescriptorLoaderTest>() { testClass<AbstractJvmRuntimeDescriptorLoaderTest>() {
model("loadJava/compiledKotlin") model("loadJava/compiledKotlin")
model("loadJava/compiledJava", extension = "java", excludeDirs = listOf("sam", "kotlinSignature/propagation")) model("loadJava/compiledJava", extension = "java", excludeDirs = listOf("sam", "kotlinSignature/propagation"))
@@ -239,6 +239,7 @@ public class KotlinBytecodeToolWindow extends JPanel implements Disposable {
generateClassFilter, generateClassFilter,
!enableInline, !enableInline,
!enableOptimization, !enableOptimization,
/*useTypeTableInSerializer=*/false,
/*packageFacadesAsMultifileClasses=*/false, /*packageFacadesAsMultifileClasses=*/false,
sink); sink);
KotlinCodegenFacade.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION); KotlinCodegenFacade.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION);