From a0895e9046de96a75593ff5a9eda98c2006051ae Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 14 May 2013 12:50:05 +0400 Subject: [PATCH] Serializing/Deserializing simple and qualified names --- .../serialization/ClassResolver.java | 28 +++++ .../descriptors/serialization/Interner.java | 67 +++++++++++ .../serialization/NameResolver.java | 94 +++++++++++++++ .../serialization/NameSerializationUtil.java | 47 ++++++++ .../descriptors/serialization/NameTable.java | 110 ++++++++++++++++++ 5 files changed, 346 insertions(+) create mode 100644 compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/ClassResolver.java create mode 100644 compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/Interner.java create mode 100644 compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameResolver.java create mode 100644 compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameSerializationUtil.java create mode 100644 compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameTable.java diff --git a/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/ClassResolver.java b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/ClassResolver.java new file mode 100644 index 00000000000..1184c91b4b9 --- /dev/null +++ b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/ClassResolver.java @@ -0,0 +1,28 @@ +/* + * Copyright 2010-2013 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.jet.descriptors.serialization; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.resolve.name.FqName; + +public interface ClassResolver { + + @Nullable + ClassDescriptor findClass(@NotNull FqName fqName); +} diff --git a/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/Interner.java b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/Interner.java new file mode 100644 index 00000000000..6c7816c4bbf --- /dev/null +++ b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/Interner.java @@ -0,0 +1,67 @@ +/* + * Copyright 2010-2013 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.jet.descriptors.serialization; + +import gnu.trove.TObjectHashingStrategy; +import gnu.trove.TObjectIntHashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public final class Interner { + private final Interner parent; + private final int firstIndex; + private final TObjectIntHashMap interned; + private final List all = new ArrayList(); + + public Interner(Interner parent, @NotNull TObjectHashingStrategy hashing) { + this.parent = parent; + this.firstIndex = parent == null ? 0 : parent.all.size(); + this.interned = new TObjectIntHashMap(hashing); + } + + public Interner(@NotNull TObjectHashingStrategy hashing) { + this(null, hashing); + } + + public Interner(@Nullable Interner parent) { + //noinspection unchecked + this(parent, TObjectHashingStrategy.CANONICAL); + } + + public Interner() { + //noinspection unchecked + this((Interner) null); + } + + public int intern(@NotNull T obj) { + assert parent == null || parent.all.size() == firstIndex : "Parent changed in parallel with child: indexes will be wrong"; + if (interned.contains(obj)) { + return interned.get(obj); + } + int index = firstIndex + interned.size(); + interned.put(obj, index); + all.add(obj); + return index; + } + + public List getAllInternedObjects() { + return all; + } +} diff --git a/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameResolver.java b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameResolver.java new file mode 100644 index 00000000000..dc727f18197 --- /dev/null +++ b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameResolver.java @@ -0,0 +1,94 @@ +/* + * Copyright 2010-2013 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.jet.descriptors.serialization; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.resolve.name.FqName; +import org.jetbrains.jet.lang.resolve.name.Name; + +public class NameResolver { + private final ProtoBuf.SimpleNameTable simpleNames; + private final ProtoBuf.QualifiedNameTable qualifiedNames; + private final ClassDescriptor[] classDescriptors; + private final ClassResolver classResolver; + + public NameResolver( + @NotNull ProtoBuf.SimpleNameTable simpleNames, + @NotNull ProtoBuf.QualifiedNameTable qualifiedNames, + @NotNull ClassResolver classResolver + ) { + this.simpleNames = simpleNames; + this.qualifiedNames = qualifiedNames; + this.classDescriptors = new ClassDescriptor[qualifiedNames.getQualifiedNamesCount()]; + this.classResolver = classResolver; + } + + @NotNull + public Name getName(int index) { + String name = simpleNames.getNames(index); + return Name.identifier(name); + } + + @Nullable + public ClassDescriptor getClassDescriptor(int fqNameIndex) { + if (classDescriptors[fqNameIndex] != null) { + return classDescriptors[fqNameIndex]; + } + + ProtoBuf.QualifiedNameTable.QualifiedName fqNameProto = qualifiedNames.getQualifiedNames(fqNameIndex); + assert fqNameProto.getKind() == ProtoBuf.QualifiedNameTable.QualifiedName.Kind.CLASS : "Not a class fqName: " + getFqName(fqNameIndex); + + if (fqNameProto.hasParentQualifiedName()) { + int parentFqNameIndex = fqNameProto.getParentQualifiedName(); + ProtoBuf.QualifiedNameTable.QualifiedName parentFqNameProto = qualifiedNames.getQualifiedNames(parentFqNameIndex); + switch (fqNameProto.getKind()) { + case CLASS: + return classResolver.findClass(getFqName(fqNameIndex)); + case PACKAGE: + Name name = getName(fqNameProto.getShortName()); + ClassDescriptor outerClass = getClassDescriptor(parentFqNameIndex); + if (outerClass == null) return null; + + return (ClassDescriptor) outerClass.getUnsubstitutedInnerClassesScope().getClassifier(name); + } + throw new IllegalStateException("Unknown kind: " + fqNameProto); + } + else { + FqName fqName = FqName.topLevel(getName(fqNameProto.getShortName())); + return classResolver.findClass(fqName); + } + } + + @NotNull + public FqName getFqName(int index) { + ProtoBuf.QualifiedNameTable.QualifiedName fqNameProto = qualifiedNames.getQualifiedNames(index); + StringBuilder sb = renderFqName(new StringBuilder(), fqNameProto); + return new FqName(sb.toString()); + } + + private StringBuilder renderFqName(StringBuilder sb, ProtoBuf.QualifiedNameTable.QualifiedName fqNameProto) { + if (fqNameProto.hasParentQualifiedName()) { + ProtoBuf.QualifiedNameTable.QualifiedName parentProto = qualifiedNames.getQualifiedNames(fqNameProto.getParentQualifiedName()); + renderFqName(sb, parentProto); + sb.append("."); + } + sb.append(simpleNames.getNames(fqNameProto.getShortName())); + return sb; + } +} diff --git a/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameSerializationUtil.java b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameSerializationUtil.java new file mode 100644 index 00000000000..ccfd5ea5fa4 --- /dev/null +++ b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameSerializationUtil.java @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2013 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.jet.descriptors.serialization; + +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class NameSerializationUtil { + @NotNull + public static NameResolver deserializeNameResolver(@NotNull InputStream in, @NotNull ClassResolver classResolver) + throws IOException { + ProtoBuf.SimpleNameTable simpleNames = ProtoBuf.SimpleNameTable.parseDelimitedFrom(in); + ProtoBuf.QualifiedNameTable qualifiedNames = ProtoBuf.QualifiedNameTable.parseDelimitedFrom(in); + return new NameResolver(simpleNames, qualifiedNames, classResolver); + } + + public static void serializeNameTable(@NotNull OutputStream out, @NotNull NameTable nameTable) throws IOException { + ProtoBuf.SimpleNameTable.Builder simpleNames = ProtoBuf.SimpleNameTable.newBuilder(); + for (String simpleName : nameTable.getSimpleNames()) { + simpleNames.addNames(simpleName); + } + simpleNames.build().writeDelimitedTo(out); + + ProtoBuf.QualifiedNameTable.Builder qualifiedNames = ProtoBuf.QualifiedNameTable.newBuilder(); + for (ProtoBuf.QualifiedNameTable.QualifiedName.Builder qName : nameTable.getFqNames()) { + qualifiedNames.addQualifiedNames(qName); + } + qualifiedNames.build().writeDelimitedTo(out); + } +} diff --git a/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameTable.java b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameTable.java new file mode 100644 index 00000000000..4d62bab0666 --- /dev/null +++ b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameTable.java @@ -0,0 +1,110 @@ +/* + * Copyright 2010-2013 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.jet.descriptors.serialization; + +import gnu.trove.TObjectHashingStrategy; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; +import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorParent; +import org.jetbrains.jet.lang.resolve.DescriptorUtils; +import org.jetbrains.jet.lang.resolve.name.Name; + +import java.util.List; + +import static org.jetbrains.jet.descriptors.serialization.ProtoBuf.QualifiedNameTable.QualifiedName; + +public class NameTable { + public static final TObjectHashingStrategy QUALIFIED_NAME_BUILDER_HASHING = + new TObjectHashingStrategy() { + @Override + public int computeHashCode(QualifiedName.Builder object) { + int result = 13; + result = 31 * result + object.getParentQualifiedName(); + result = 31 * result + object.getShortName(); + result = 31 * result + object.getKind().hashCode(); + return result; + } + + @Override + public boolean equals( + QualifiedName.Builder o1, QualifiedName.Builder o2 + ) { + return o1.getParentQualifiedName() == o2.getParentQualifiedName() + && o1.getShortName() == o2.getShortName() + && o1.getKind() == o2.getKind(); + } + }; + + private final Interner simpleNames = new Interner(); + private final Interner qualifiedNames = new Interner(QUALIFIED_NAME_BUILDER_HASHING); + + @NotNull + public List getSimpleNames() { + return simpleNames.getAllInternedObjects(); + } + + @NotNull + public List getFqNames() { + return qualifiedNames.getAllInternedObjects(); + } + + public int getSimpleNameIndex(@NotNull Name name) { + return simpleNames.intern(name.asString()); + } + + public int getFqNameIndex(@NotNull ClassDescriptor classDescriptor) { + QualifiedName.Builder builder = QualifiedName.newBuilder(); + builder.setKind(QualifiedName.Kind.CLASS); + builder.setShortName(getSimpleNameIndex(classDescriptor.getName())); + + DeclarationDescriptor containingDeclaration = classDescriptor.getContainingDeclaration(); + if (containingDeclaration instanceof NamespaceDescriptor) { + NamespaceDescriptor namespaceDescriptor = (NamespaceDescriptor) containingDeclaration; + builder.setParentQualifiedName(getFqNameIndex(namespaceDescriptor)); + } + else { + ClassDescriptor outerClass = (ClassDescriptor) containingDeclaration; + builder.setParentQualifiedName(getFqNameIndex(outerClass)); + } + + return qualifiedNames.intern(builder); + } + + public int getFqNameIndex(@NotNull NamespaceDescriptor namespaceDescriptor) { + QualifiedName.Builder builder = QualifiedName.newBuilder(); + //default: builder.setKind(QualifiedNameTable.QualifiedName.Kind.PACKAGE); + builder.setShortName(getSimpleNameIndex(namespaceDescriptor.getName())); + + NamespaceDescriptorParent containingDeclaration = namespaceDescriptor.getContainingDeclaration(); + if (containingDeclaration instanceof NamespaceDescriptor) { + NamespaceDescriptor parentNamespace = (NamespaceDescriptor) containingDeclaration; + if (!DescriptorUtils.isRootNamespace(parentNamespace)) { + builder.setParentQualifiedName(getFqNameIndex(parentNamespace)); + } + } + else { + builder.clearParentQualifiedName(); + } + + return qualifiedNames.intern(builder); + } + + + +}