stub hierarchy: replace qualified name interning with hashing

This commit is contained in:
peter
2016-07-05 22:09:53 +02:00
parent b908d5f2c2
commit d42b29725e
8 changed files with 46 additions and 102 deletions
@@ -103,11 +103,11 @@ class Imports {
}
class Import {
@QNameId final int qualifier;
@QNameHash final int qualifier;
@ShortName final int importedName; // 0 for on-demand
final boolean isStatic;
Import(@QNameId int qualifier, @ShortName int importedName, boolean isStatic) {
Import(@QNameHash int qualifier, @ShortName int importedName, boolean isStatic) {
this.qualifier = qualifier;
this.importedName = importedName;
this.isStatic = isStatic;
@@ -126,10 +126,10 @@ class Import {
class AliasedImport extends Import {
private final @ShortName int alias;
public AliasedImport(@QNameId int qualifier,
@ShortName int importedName,
boolean isStatic,
@ShortName int alias) {
AliasedImport(@QNameHash int qualifier,
@ShortName int importedName,
boolean isStatic,
@ShortName int alias) {
super(qualifier, importedName, isStatic);
this.alias = alias;
}
@@ -19,7 +19,6 @@ import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.psi.CommonClassNames;
import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
import com.intellij.util.io.DataInputOutputUtil;
import gnu.trove.TLongIntHashMap;
import java.io.DataInput;
import java.io.DataOutput;
@@ -28,31 +27,19 @@ import java.io.IOException;
class NameEnvironment extends UserDataHolderBase {
public static final int OBJECT_NAME = IndexTree.hashIdentifier("Object");
public static final int NO_NAME = 0;
@QNameId public final int java_lang;
@QNameHash final int java_lang;
public final QualifiedName java_lang_Enum;
public final QualifiedName java_lang_annotation_Annotation;
private final TLongIntHashMap myConcatenations = new TLongIntHashMap();
NameEnvironment() {
java_lang = fromString("java.lang");
java_lang_Enum = new QualifiedName.Interned(fromString(CommonClassNames.JAVA_LANG_ENUM));
java_lang_annotation_Annotation = new QualifiedName.Interned(fromString(CommonClassNames.JAVA_LANG_ANNOTATION_ANNOTATION));
}
@QNameId
int fromString(String s) {
return internQualifiedName(IndexTree.hashQualifiedName(s));
}
@QNameId int findExistingName(@QNameId int stemId, @ShortName int suffix) {
int existing = myConcatenations.get(pack(stemId, suffix));
return existing > 0 ? existing : -1;
}
@QNameId int internQualifiedName(@ShortName int[] qname) {
@QNameHash int fromString(String s) {
int id = 0;
for (int shortName : qname) {
for (int shortName : IndexTree.hashQualifiedName(s)) {
id = qualifiedName(id, shortName);
}
return id;
@@ -61,7 +48,7 @@ class NameEnvironment extends UserDataHolderBase {
/**
* @see SerializedUnit#writeQualifiedName(DataOutput, int[])
*/
@QNameId int readQualifiedName(DataInput in) throws IOException {
@QNameHash int readQualifiedName(DataInput in) throws IOException {
int id = 0;
int len = DataInputOutputUtil.readINT(in);
for (int i = 0; i < len; i++) {
@@ -70,22 +57,13 @@ class NameEnvironment extends UserDataHolderBase {
return id;
}
int memberQualifiedName(@QNameId int ownerName, @ShortName int name) {
return name == NO_NAME || ownerName < 0 ? -1 : qualifiedName(ownerName, name);
int memberQualifiedName(@QNameHash int ownerName, @ShortName int name) {
return name == NO_NAME || ownerName == 0 ? 0 : qualifiedName(ownerName, name);
}
@QNameId int qualifiedName(@QNameId int prefix, @ShortName int shortName) {
int existing = findExistingName(prefix, shortName);
return existing >= 0 ? existing : addName(prefix, shortName);
@QNameHash int qualifiedName(@QNameHash int prefix, @ShortName int shortName) {
int hash = prefix * 31 + shortName;
return hash == 0 ? 1 : hash;
}
private int addName(@QNameId int stemId, @ShortName int suffix) {
int newId = myConcatenations.size();
myConcatenations.put(pack(stemId, suffix), newId);
return newId;
}
private static long pack(@QNameId int stemId, @ShortName int suffix) {
return ((long)suffix << 32) + stemId;
}
}
@@ -69,7 +69,7 @@ class SerializedUnit {
/**
* @see NameEnvironment#readQualifiedName(DataInput)
*/
static void writeQualifiedName(DataOutput out, @QNameId int[] array) throws IOException {
static void writeQualifiedName(DataOutput out, @QNameHash int[] array) throws IOException {
DataInputOutputUtil.writeINT(out, array.length);
for (int i : array) {
out.writeInt(i);
@@ -124,13 +124,13 @@ class SerializedUnit {
writeMembers(out, value.myDecls);
}
private static ClassSymbol readClassDecl(UnitInputStream in, UnitInfo info, Symbol owner, @QNameId int ownerName) throws IOException {
private static ClassSymbol readClassDecl(UnitInputStream in, UnitInfo info, Symbol owner, @QNameHash int ownerName) throws IOException {
int stubId = DataInputOutputUtil.readINT(in);
int mods = DataInputOutputUtil.readINT(in);
@ShortName int name = in.readInt();
@CompactArray(QualifiedName.class) Object superNames = readSupers(in, info.isCompiled());
@QNameId int qname = in.names.memberQualifiedName(ownerName, name);
@QNameHash int qname = in.names.memberQualifiedName(ownerName, name);
ClassSymbol symbol = in.stubEnter.classEnter(info, owner, stubId, mods, name, superNames, qname, in.fileId);
readMembers(in, info, qname, symbol);
@@ -173,7 +173,7 @@ class SerializedUnit {
private static void readMembers(UnitInputStream in,
UnitInfo info,
@QNameId int ownerName,
@QNameHash int ownerName,
MemberSymbol symbol) throws IOException {
int memberCount = DataInputOutputUtil.readINT(in);
if (memberCount == 0) return;
@@ -197,7 +197,7 @@ class SerializedUnit {
}
}
private static ClassSymbol readDecl(UnitInputStream in, UnitInfo info, Symbol owner, @QNameId int ownerName) throws IOException {
private static ClassSymbol readDecl(UnitInputStream in, UnitInfo info, Symbol owner, @QNameHash int ownerName) throws IOException {
if (in.readBoolean()) {
return readClassDecl(in, info, owner, ownerName);
}
@@ -60,7 +60,7 @@ public class StubEnter {
int mods,
@ShortName int name,
@CompactArray(QualifiedName.class) Object superNames,
@QNameId int qname, int fileId) throws IOException {
@QNameHash int qname, int fileId) throws IOException {
int flags = checkFlags(mods, info.isCompiled());
@CompactArray(QualifiedName.class) Object supers = handleSpecialSupers(mods, superNames);
@@ -69,9 +69,7 @@ public class StubResolver {
findGlobalType(info, name, result);
if (processPackages) {
@QNameId int nameId = myNameEnvironment.findExistingName(0, name);
Symbol.PackageSymbol pkg = nameId < 0 ? null : mySymbols.getPackage(nameId);
ContainerUtil.addIfNotNull(result, pkg);
ContainerUtil.addIfNotNull(result, mySymbols.getPackage(name));
}
return result;
}
@@ -93,10 +91,7 @@ public class StubResolver {
}
private void findIdentInPackage(Symbol.PackageSymbol pck, @ShortName int name, boolean processPackages, Set<Symbol> symbols) {
@QNameId int fullname = mySymbols.myNameEnvironment.findExistingName(pck.myQualifiedName, name);
if (fullname < 0) {
return;
}
@QNameHash int fullname = mySymbols.myNameEnvironment.qualifiedName(pck.myQualifiedName, name);
if (processPackages) {
ContainerUtil.addIfNotNull(symbols, mySymbols.getPackage(fullname));
}
@@ -132,8 +127,8 @@ public class StubResolver {
}
}
public Symbol.ClassSymbol[] findGlobalType(@QNameId int nameId) {
return mySymbols.loadClass(nameId);
public Symbol.ClassSymbol[] findGlobalType(@QNameHash int nameId) {
return mySymbols.getClassSymbols(nameId);
}
private void findGlobalType(UnitInfo info, @ShortName int name, Set<Symbol> symbols) throws IncompleteHierarchyException {
@@ -168,11 +163,8 @@ public class StubResolver {
}
// handling of `import prefix.*`
private void importAll(@QNameId int prefix, @ShortName int suffix, final Set<Symbol> symbols) {
@QNameId int fullname = myNameEnvironment.findExistingName(prefix, suffix);
if (fullname >= 0) {
Collections.addAll(symbols, findGlobalType(fullname));
}
private void importAll(@QNameHash int prefix, @ShortName int suffix, final Set<Symbol> symbols) {
Collections.addAll(symbols, findGlobalType(myNameEnvironment.qualifiedName(prefix, suffix)));
}
// handling of import static `tsym.name` as
@@ -68,9 +68,9 @@ abstract class Symbol {
}
public static class PackageSymbol extends Symbol {
@QNameId final int myQualifiedName;
@QNameHash final int myQualifiedName;
public PackageSymbol(Symbol owner, @QNameId int fullname, int name) {
public PackageSymbol(Symbol owner, @QNameHash int fullname, int name) {
super(IndexTree.PACKAGE, owner, name);
myQualifiedName = fullname;
}
@@ -2,6 +2,7 @@ package com.intellij.psi.stubsHierarchy.impl;
import com.intellij.psi.stubsHierarchy.impl.Symbol.ClassSymbol;
import com.intellij.psi.stubsHierarchy.impl.Symbol.PackageSymbol;
import com.intellij.util.ArrayUtil;
import gnu.trove.TIntObjectHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -10,7 +11,7 @@ import java.util.ArrayList;
import java.util.List;
public class Symbols {
public final PackageSymbol myRootPackage;
public final PackageSymbol myRootPackage = new PackageSymbol(null, 0, NameEnvironment.NO_NAME);
protected final NameEnvironment myNameEnvironment = new NameEnvironment();
private final AnchorRepository myClassAnchors = new AnchorRepository();
@@ -18,14 +19,13 @@ public class Symbols {
// fullName -> PackageSymbol
private final TIntObjectHashMap<PackageSymbol> myPackages = new TIntObjectHashMap<>();
// nameId -> ClassSymbols (used by global resolve)
private Object[] myClassSymbolsByNameId = new Object[0x8000];
private TIntObjectHashMap<Object> myClassSymbolsByNameId = new TIntObjectHashMap<>();
protected Symbols() {
myRootPackage = new PackageSymbol(null, 0, NameEnvironment.NO_NAME);
myPackages.put(0, myRootPackage);
}
PackageSymbol enterPackage(@QNameId int qualifiedName, @ShortName int shortName, PackageSymbol owner) {
PackageSymbol enterPackage(@QNameHash int qualifiedName, @ShortName int shortName, PackageSymbol owner) {
PackageSymbol p = myPackages.get(qualifiedName);
if (p == null) {
p = new PackageSymbol(owner, qualifiedName, shortName);
@@ -35,17 +35,13 @@ public class Symbols {
}
@Nullable
PackageSymbol getPackage(@QNameId int qualifiedName) {
PackageSymbol getPackage(@QNameHash int qualifiedName) {
return myPackages.get(qualifiedName);
}
@NotNull
ClassSymbol[] loadClass(@QNameId int name) {
return name >= myClassSymbolsByNameId.length ? ClassSymbol.EMPTY_ARRAY : getClassSymbols(name);
}
private ClassSymbol[] getClassSymbols(int id) {
Object cs = myClassSymbolsByNameId[id];
ClassSymbol[] getClassSymbols(@QNameHash int name) {
Object cs = myClassSymbolsByNameId.get(name);
if (cs == null) {
return ClassSymbol.EMPTY_ARRAY;
}
@@ -62,49 +58,27 @@ public class Symbols {
Symbol owner,
UnitInfo info,
@CompactArray(QualifiedName.class) Object supers,
@QNameId int qualifiedName) {
@QNameHash int qualifiedName) {
int anchorId = myClassAnchors.registerClass(fileId, stubId);
ClassSymbol c = new ClassSymbol(anchorId, flags, owner, shortName, info, supers);
myClassSymbols.add(c);
if (qualifiedName >= 0) {
if (qualifiedName != 0) {
putClassByName(c, qualifiedName);
}
return c;
}
private void putClassByName(ClassSymbol classSymbol, int nameId) {
ensureByNameCapacity(nameId);
Object cs = myClassSymbolsByNameId[nameId];
private void putClassByName(ClassSymbol classSymbol, @QNameHash int nameId) {
Object cs = myClassSymbolsByNameId.get(nameId);
if (cs == null) {
myClassSymbolsByNameId[nameId] = classSymbol;
myClassSymbolsByNameId.put(nameId, classSymbol);
} else if (cs instanceof ClassSymbol) {
myClassSymbolsByNameId.put(nameId, new ClassSymbol[]{(ClassSymbol)cs, classSymbol});
} else {
if (cs instanceof ClassSymbol) {
ClassSymbol c = (ClassSymbol)cs;
myClassSymbolsByNameId[nameId] = new ClassSymbol[]{c, classSymbol};
} else {
ClassSymbol[] css = (ClassSymbol[])cs;
ClassSymbol[] newCss = new ClassSymbol[css.length + 1];
System.arraycopy(css, 0, newCss, 0, css.length);
newCss[css.length] = classSymbol;
myClassSymbolsByNameId[nameId] = newCss;
}
myClassSymbolsByNameId.put(nameId, ArrayUtil.append((ClassSymbol[])cs, classSymbol));
}
}
private void ensureByNameCapacity(int maxIndex) {
if (maxIndex >= myClassSymbolsByNameId.length) {
int newLength = calculateNewLength(myClassSymbolsByNameId.length, maxIndex);
Object[] result = new Object[newLength];
System.arraycopy(myClassSymbolsByNameId, 0, result, 0, myClassSymbolsByNameId.length);
myClassSymbolsByNameId = result;
}
}
private static int calculateNewLength(int currentLength, int maxIndex) {
while (currentLength < maxIndex + 1) currentLength *= 2;
return currentLength;
}
SingleClassHierarchy createHierarchy() {
ClassSymbol[] array = myClassSymbols.toArray(ClassSymbol.EMPTY_ARRAY);
myClassSymbols = null;
@@ -36,11 +36,11 @@ import java.lang.annotation.Target;
}
/**
* int id of a qualified name in a {@link NameEnvironment}
* int hash of a qualified name by {@link NameEnvironment}
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE_USE)
@interface QNameId { }
@interface QNameHash { }
/**
* int hash of a qualified name part, produced by {@link IndexTree#hashIdentifier(String)}