mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
stub hierarchy: replace qualified name interning with hashing
This commit is contained in:
@@ -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)}
|
||||
|
||||
Reference in New Issue
Block a user