1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-08 18:26:01 +02:00

2004-06-17 Alain Magloire

Changes from Chris Wiebe to deal
	with the memory consumption.
This commit is contained in:
Alain Magloire 2004-06-17 19:20:08 +00:00
parent 954d5b8b45
commit d52cb5e624
9 changed files with 199 additions and 166 deletions

View file

@ -1,3 +1,8 @@
2004-06-17 Alain Magloire
Changes from Chris Wiebe to deal
with the memory consumption.
2004-05-12 Chris Wiebe
Heavy refactoring of type cache to address scalability
concerns.

View file

@ -35,6 +35,11 @@ public interface ITypeInfo extends Comparable {
*/
public int getCElementType();
/**
* Sets the CElement type.
*/
public void setCElementType(int type);
/**
* Gets the type name.
*/

View file

@ -97,7 +97,6 @@ public class QualifiedTypeName implements IQualifiedTypeName {
return null;
}
// TODO extra methods eg matchingFirstSegments() etc
public boolean isEmpty() {
return fSegments.length == 0;
}
@ -179,7 +178,7 @@ public class QualifiedTypeName implements IQualifiedTypeName {
public IQualifiedTypeName removeFirstSegments(int count) {
if (count == 0) {
return new QualifiedTypeName(this);
return this;
} else if (count >= fSegments.length || count < 0) {
return new QualifiedTypeName(new String[0]);
} else {
@ -192,7 +191,7 @@ public class QualifiedTypeName implements IQualifiedTypeName {
public IQualifiedTypeName removeLastSegments(int count) {
if (count == 0) {
return new QualifiedTypeName(this);
return this;
} else if (count >= fSegments.length || count < 0) {
return new QualifiedTypeName(new String[0]);
} else {

View file

@ -10,10 +10,6 @@
*******************************************************************************/
package org.eclipse.cdt.core.browser;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.internal.core.browser.cache.ITypeCache;
import org.eclipse.cdt.internal.core.browser.util.ArrayUtil;
@ -23,26 +19,44 @@ public class TypeInfo implements ITypeInfo
{
protected ITypeCache fTypeCache;
protected int fElementType;
protected QualifiedTypeName fQualifiedName;
protected Set fSourceRefs = new HashSet();
protected IQualifiedTypeName fQualifiedName;
protected ITypeReference[] fSourceRefs = null;
protected int fSourceRefsCount = 0;
protected final static int INITIAL_REFS_SIZE = 1;
protected final static int REFS_GROW_BY = 10;
protected final static ITypeInfo[] EMPTY_TYPES = new ITypeInfo[0];
public TypeInfo(int elementType, IQualifiedTypeName typeName) {
fElementType = elementType;
fQualifiedName = new QualifiedTypeName(typeName);
fQualifiedName = typeName;
}
public void addReference(ITypeReference location) {
fSourceRefs.add(location);
if (fSourceRefs == null) {
fSourceRefs = new ITypeReference[INITIAL_REFS_SIZE];
fSourceRefsCount = 0;
} else if (fSourceRefsCount == fSourceRefs.length) {
ITypeReference[] refs = new ITypeReference[fSourceRefs.length + REFS_GROW_BY];
System.arraycopy(fSourceRefs, 0, refs, 0, fSourceRefsCount);
fSourceRefs = refs;
}
fSourceRefs[fSourceRefsCount] = location;
++fSourceRefsCount;
}
public ITypeReference[] getReferences() {
return (ITypeReference[]) fSourceRefs.toArray(new ITypeReference[fSourceRefs.size()]);
if (fSourceRefs != null) {
ITypeReference[] refs = new ITypeReference[fSourceRefsCount];
System.arraycopy(fSourceRefs, 0, refs, 0, fSourceRefsCount);
return refs;
}
return null;
}
public ITypeReference getResolvedReference() {
for (Iterator i = fSourceRefs.iterator(); i.hasNext(); ) {
ITypeReference location = (ITypeReference) i.next();
for (int i = 0; i < fSourceRefsCount; ++i) {
ITypeReference location = fSourceRefs[i];
if (location.getLength() != 0) {
return location;
}
@ -51,7 +65,7 @@ public class TypeInfo implements ITypeInfo
}
public boolean isReferenced() {
return !fSourceRefs.isEmpty();
return (fSourceRefs != null);
}
public boolean isUndefinedType() {
@ -171,12 +185,12 @@ public class TypeInfo implements ITypeInfo
return true;
// check if path is in scope
for (Iterator i = fSourceRefs.iterator(); i.hasNext(); ) {
ITypeReference location = (ITypeReference) i.next();
for (int i = 0; i < fSourceRefsCount; ++i) {
ITypeReference location = fSourceRefs[i];
if (scope.encloses(location.getPath()))
return true;
}
return false;
}

View file

@ -149,18 +149,28 @@ public class IndexerTypesJob extends IndexerJob {
int[] references = entry.getFileReferences();
if (references != null && references.length > 0) {
// add new type to cache
info = new TypeInfo(type, qualifiedName);
fTypeCache.insert(info);
if (info != null) {
info.setCElementType(type);
} else {
info = new TypeInfo(type, qualifiedName);
fTypeCache.insert(info);
}
for (int i = 0; i < references.length; ++i) {
if (monitor.isCanceled())
throw new InterruptedException();
IndexedFile file = input.getIndexedFile(references[i]);
if (file != null && file.getPath() != null) {
IPath path = PathUtil.getWorkspaceRelativePath(file.getPath());
info.addReference(new TypeReference(path, project));
}
// for (int i = 0; i < references.length; ++i) {
// if (monitor.isCanceled())
// throw new InterruptedException();
//
// IndexedFile file = input.getIndexedFile(references[i]);
// if (file != null && file.getPath() != null) {
// IPath path = PathUtil.getWorkspaceRelativePath(file.getPath());
// info.addReference(new TypeReference(path, project));
// }
// }
// just grab the first reference
IndexedFile file = input.getIndexedFile(references[0]);
if (file != null && file.getPath() != null) {
IPath path = PathUtil.getWorkspaceRelativePath(file.getPath());
info.addReference(new TypeReference(path, project));
}
}
}

View file

@ -44,12 +44,14 @@ import org.eclipse.core.runtime.jobs.Job;
public class TypeCache implements ITypeCache {
private static final int INITIAL_TYPE_COUNT = 100;
private final Map fTypeNameMap = new HashMap(INITIAL_TYPE_COUNT);
private final Map fTypeKeyMap = new HashMap(INITIAL_TYPE_COUNT);
private final IProject fProject;
private final IWorkingCopyProvider fWorkingCopyProvider;
private final Collection fDeltas = new ArrayList();
private final ITypeInfo fGlobalNamespace;
private static final int[] ENCLOSING_TYPES = {ICElement.C_NAMESPACE, ICElement.C_CLASS, ICElement.C_STRUCT, 0};
private IJobChangeListener fJobChangeListener = new IJobChangeListener() {
public void aboutToRun(IJobChangeEvent event) {
}
@ -94,7 +96,8 @@ public class TypeCache implements ITypeCache {
private static class GlobalNamespace implements IQualifiedTypeName {
private static final String GLOBAL_NAMESPACE = TypeCacheMessages.getString("TypeCache.globalNamespace"); //$NON-NLS-1$
private static final String[] segments = new String[] { GLOBAL_NAMESPACE };
public GlobalNamespace() {
}
@ -127,7 +130,7 @@ public class TypeCache implements ITypeCache {
}
public String[] segments() {
return new String[] { GLOBAL_NAMESPACE };
return segments;
}
public String segment(int index) {
@ -161,11 +164,11 @@ public class TypeCache implements ITypeCache {
}
public IQualifiedTypeName removeFirstSegments(int count) {
return new QualifiedTypeName(this);
return this;
}
public IQualifiedTypeName removeLastSegments(int count) {
return new QualifiedTypeName(this);
return this;
}
public boolean isLowLevel() {
@ -207,6 +210,28 @@ public class TypeCache implements ITypeCache {
}
}
private static class HashKey {
private IQualifiedTypeName name;
private int type;
public HashKey(IQualifiedTypeName name, int type) {
this.name = name;
this.type = type;
}
public int hashCode() {
return (this.name.hashCode() + this.type);
}
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof HashKey)) {
return false;
}
HashKey otherKey = (HashKey)obj;
return (this.type == otherKey.type && this.name.equals(otherKey.name));
}
}
public TypeCache(IProject project, IWorkingCopyProvider workingCopyProvider) {
fProject = project;
fWorkingCopyProvider = workingCopyProvider;
@ -240,89 +265,49 @@ public class TypeCache implements ITypeCache {
}
public synchronized boolean isEmpty() {
return fTypeNameMap.isEmpty();
return fTypeKeyMap.isEmpty();
}
public synchronized void insert(ITypeInfo newType) {
// check if type already exists
Collection typeCollection = (Collection) fTypeNameMap.get(newType.getName());
if (typeCollection != null) {
for (Iterator typeIter = typeCollection.iterator(); typeIter.hasNext(); ) {
ITypeInfo currType = (ITypeInfo) typeIter.next();
if (currType.canSubstituteFor(newType)) {
// merge references into new type
ITypeReference[] refs = currType.getReferences();
for (int i = 0; i < refs.length; ++i) {
newType.addReference(refs[i]);
}
// remove the old type
currType.setCache(null);
typeIter.remove();
}
}
}
public synchronized void insert(ITypeInfo newType) {
// check if enclosing types are already in cache
IQualifiedTypeName enclosingName = newType.getQualifiedTypeName().getEnclosingTypeName();
if (enclosingName != null) {
while (!enclosingName.isEmpty()) {
boolean foundType = false;
Collection enclosingCollection = (Collection) fTypeNameMap.get(enclosingName.getName());
if (enclosingCollection == null) {
enclosingCollection = new HashSet();
fTypeNameMap.put(enclosingName.getName(), enclosingCollection);
} else {
for (Iterator typeIter = enclosingCollection.iterator(); typeIter.hasNext(); ) {
ITypeInfo curr = (ITypeInfo) typeIter.next();
if (curr.getQualifiedTypeName().equals(enclosingName)) {
foundType = true;
break;
}
}
// try namespace, class, struct, then undefined
ITypeInfo enclosingType = null;
for (int i = 0; enclosingType == null && i < ENCLOSING_TYPES.length; ++i) {
enclosingType = (ITypeInfo) fTypeKeyMap.get(new HashKey(enclosingName, ENCLOSING_TYPES[i]));
}
if (!foundType) {
if (enclosingType == null) {
// create a dummy type to take this place (type 0 == unknown)
ITypeInfo dummyType = new TypeInfo(0, enclosingName);
enclosingCollection.add(dummyType);
dummyType.setCache(this);
fTypeKeyMap.put(new HashKey(enclosingName, 0), dummyType);
}
enclosingName = enclosingName.removeLastSegments(1);
}
}
typeCollection = (Collection) fTypeNameMap.get(newType.getName());
if (typeCollection == null) {
typeCollection = new HashSet();
fTypeNameMap.put(newType.getName(), typeCollection);
}
typeCollection.add(newType);
fTypeKeyMap.put(new HashKey(newType.getQualifiedTypeName(), newType.getCElementType()), newType);
newType.setCache(this);
}
public synchronized void remove(ITypeInfo info) {
Collection typeCollection = (Collection) fTypeNameMap.get(info.getName());
if (typeCollection != null) {
info.setCache(null);
typeCollection.remove(info);
}
fTypeKeyMap.remove(new HashKey(info.getQualifiedTypeName(), info.getCElementType()));
info.setCache(null);
}
public synchronized void flush(ITypeSearchScope scope) {
if (scope.encloses(fProject)) {
flushAll();
} else {
for (Iterator mapIter = fTypeNameMap.entrySet().iterator(); mapIter.hasNext(); ) {
for (Iterator mapIter = fTypeKeyMap.entrySet().iterator(); mapIter.hasNext(); ) {
Map.Entry entry = (Map.Entry) mapIter.next();
Collection typeCollection = (Collection) entry.getValue();
for (Iterator typeIter = typeCollection.iterator(); typeIter.hasNext(); ) {
ITypeInfo info = (ITypeInfo) typeIter.next();
if (info.isEnclosed(scope)) {
info.setCache(null);
typeIter.remove();
}
}
if (typeCollection.isEmpty())
ITypeInfo info = (ITypeInfo) entry.getValue();
if (info.isEnclosed(scope)) {
mapIter.remove();
}
}
}
}
@ -342,19 +327,16 @@ public class TypeCache implements ITypeCache {
}
public boolean shouldContinue() { return true; }
});
fTypeNameMap.clear();
fTypeKeyMap.clear();
}
public synchronized void accept(ITypeInfoVisitor visitor) {
for (Iterator mapIter = fTypeNameMap.entrySet().iterator(); mapIter.hasNext(); ) {
for (Iterator mapIter = fTypeKeyMap.entrySet().iterator(); mapIter.hasNext(); ) {
Map.Entry entry = (Map.Entry) mapIter.next();
Collection typeCollection = (Collection) entry.getValue();
for (Iterator typeIter = typeCollection.iterator(); typeIter.hasNext(); ) {
ITypeInfo info = (ITypeInfo) typeIter.next();
if (!visitor.shouldContinue())
return; // stop visiting
visitor.visit(info);
}
ITypeInfo info = (ITypeInfo) entry.getValue();
if (!visitor.shouldContinue())
return; // stop visiting
visitor.visit(info);
}
}
@ -364,10 +346,12 @@ public class TypeCache implements ITypeCache {
public boolean visit(ITypeInfo info) {
if (scope == null || info.isEnclosed(scope)) {
ITypeReference[] refs = info.getReferences();
for (int i = 0; i < refs.length; ++i) {
IPath path = refs[i].getPath();
if (scope == null || scope.encloses(path))
pathSet.add(path);
if (refs != null) {
for (int i = 0; i < refs.length; ++i) {
IPath path = refs[i].getPath();
if (scope == null || scope.encloses(path))
pathSet.add(path);
}
}
}
return true;
@ -393,51 +377,38 @@ public class TypeCache implements ITypeCache {
public synchronized ITypeInfo[] getTypes(IQualifiedTypeName qualifiedName) {
Collection results = new ArrayList();
Collection typeCollection = (Collection) fTypeNameMap.get(qualifiedName.getName());
if (typeCollection != null) {
for (Iterator typeIter = typeCollection.iterator(); typeIter.hasNext(); ) {
ITypeInfo info = (ITypeInfo) typeIter.next();
if (info.getQualifiedTypeName().equals(qualifiedName)) {
results.add(info);
}
for (int i = 0; i < ITypeInfo.KNOWN_TYPES.length; ++i) {
ITypeInfo info = (ITypeInfo) fTypeKeyMap.get(new HashKey(qualifiedName, ITypeInfo.KNOWN_TYPES[i]));
if (info != null) {
results.add(info);
}
}
ITypeInfo info = (ITypeInfo) fTypeKeyMap.get(new HashKey(qualifiedName, 0));
if (info != null) {
results.add(info);
}
return (ITypeInfo[]) results.toArray(new ITypeInfo[results.size()]);
}
public synchronized ITypeInfo getType(int type, IQualifiedTypeName qualifiedName) {
Collection typeCollection = (Collection) fTypeNameMap.get(qualifiedName.getName());
if (typeCollection != null) {
for (Iterator typeIter = typeCollection.iterator(); typeIter.hasNext(); ) {
ITypeInfo info = (ITypeInfo) typeIter.next();
if ((info.getCElementType() == type || info.getCElementType() == 0)
&& info.getQualifiedTypeName().equals(qualifiedName)) {
return info;
}
}
ITypeInfo info = (ITypeInfo) fTypeKeyMap.get(new HashKey(qualifiedName, type));
if (info == null && type != 0) {
info = (ITypeInfo) fTypeKeyMap.get(new HashKey(qualifiedName, 0));
}
return null;
return info;
}
public synchronized ITypeInfo getEnclosingType(ITypeInfo info, final int[] kinds) {
IQualifiedTypeName enclosingName = info.getQualifiedTypeName().getEnclosingTypeName();
if (enclosingName != null) {
Collection typeCollection = (Collection) fTypeNameMap.get(enclosingName.getName());
if (typeCollection != null) {
// try namespace, class, struct, then undefined
final int[] validKinds = {ICElement.C_NAMESPACE, ICElement.C_CLASS, ICElement.C_STRUCT, 0};
for (int i = 0; i < validKinds.length; ++i) {
if (ArrayUtil.contains(kinds, validKinds[i])) {
for (Iterator typeIter = typeCollection.iterator(); typeIter.hasNext(); ) {
ITypeInfo type = (ITypeInfo) typeIter.next();
if (type.getCElementType() == validKinds[i]
&& type.getQualifiedTypeName().equals(enclosingName)) {
return type;
}
}
}
// try namespace, class, struct, then undefined
ITypeInfo enclosingType = null;
for (int i = 0; enclosingType == null && i < ENCLOSING_TYPES.length; ++i) {
if (ArrayUtil.contains(kinds, ENCLOSING_TYPES[i])) {
enclosingType = (ITypeInfo) fTypeKeyMap.get(new HashKey(enclosingName, ENCLOSING_TYPES[i]));
}
}
return enclosingType;
}
return null;
}
@ -451,23 +422,12 @@ public class TypeCache implements ITypeCache {
return fGlobalNamespace;
return null;
}
String[] segments = qualifiedName.segments();
String namespace = segments[0];
Collection typeCollection = (Collection) fTypeNameMap.get(namespace);
if (typeCollection != null) {
// try namespace, then undefined
final int[] kinds = {ICElement.C_NAMESPACE, 0};
for (int i = 0; i < kinds.length; ++i) {
for (Iterator typeIter = typeCollection.iterator(); typeIter.hasNext(); ) {
ITypeInfo type = (ITypeInfo) typeIter.next();
if (type.getCElementType() == kinds[i]
&& type.getQualifiedTypeName().isGlobal()) {
return type;
}
}
}
}
return null;
IQualifiedTypeName namespace = qualifiedName.removeLastSegments(qualifiedName.segmentCount()-1);
// try namespace, then undefined
ITypeInfo namespaceType = (ITypeInfo) fTypeKeyMap.get(new HashKey(namespace, ICElement.C_NAMESPACE));
if (namespaceType == null)
namespaceType = (ITypeInfo) fTypeKeyMap.get(new HashKey(namespace, 0));
return namespaceType;
}
public synchronized boolean hasEnclosedTypes(final ITypeInfo info) {

View file

@ -110,8 +110,8 @@ public class TypeParser implements ISourceElementRequestor {
private IWorkingCopyProvider fWorkingCopyProvider;
private IProgressMonitor fProgressMonitor;
private ISourceElementCallbackDelegate fLastDeclaration;
private SimpleStack fScopeStack = new SimpleStack();
private SimpleStack fResourceStack = new SimpleStack();
private final SimpleStack fScopeStack = new SimpleStack();
private final SimpleStack fResourceStack = new SimpleStack();
private ITypeInfo fTypeToFind;
private boolean fFoundType;
@ -311,6 +311,8 @@ public class TypeParser implements ISourceElementRequestor {
}
if (reader != null) {
fResourceStack.clear();
fScopeStack.clear();
fResourceStack.push(stackObject);
parseContents(path, project, reader, language, progressMonitor);
fResourceStack.pop();
@ -419,7 +421,8 @@ public class TypeParser implements ISourceElementRequestor {
} catch (ParserFactoryError e) {
CCorePlugin.log(e);
} catch (ParseError e) {
CCorePlugin.log(e);
// no need to log
// CCorePlugin.log(e);
} catch (OperationCanceledException e) {
throw new InterruptedException();
} catch (Exception e) {
@ -622,19 +625,35 @@ public class TypeParser implements ISourceElementRequestor {
return;
}
// collect enclosing names
if (fTypeToFind != null) {
if ((fTypeToFind.getCElementType() == type || fTypeToFind.isUndefinedType()) && name.equals(fTypeToFind.getName())) {
String[] enclosingNames = getEnclosingNames(offsetable);
QualifiedTypeName qualifiedName = new QualifiedTypeName(name, enclosingNames);
if (qualifiedName.equals(fTypeToFind.getQualifiedTypeName())) {
fFoundType = true;
// add types to cache
addType(type, name, enclosingNames, fResourceStack.bottom(), fResourceStack.top(), offset, end - offset);
fProgressMonitor.worked(1);
}
}
} else {
// add types to cache
addType(type, name, getEnclosingNames(offsetable), fResourceStack.bottom(), fResourceStack.top(), offset, end - offset);
fProgressMonitor.worked(1);
}
}
private String[] getEnclosingNames(IASTOffsetableNamedElement elem) {
String[] enclosingNames = null;
if (offsetable instanceof IASTQualifiedNameElement) {
String[] names = ((IASTQualifiedNameElement) offsetable).getFullyQualifiedName();
if (elem instanceof IASTQualifiedNameElement) {
String[] names = ((IASTQualifiedNameElement) elem).getFullyQualifiedName();
if (names != null && names.length > 1) {
enclosingNames = new String[names.length - 1];
System.arraycopy(names, 0, enclosingNames, 0, names.length - 1);
}
}
// add types to cache
addType(type, name, enclosingNames, fResourceStack.bottom(), fResourceStack.top(), offset, end - offset);
fProgressMonitor.worked(1);
return enclosingNames;
}
private int getElementType(IASTOffsetableNamedElement offsetable) {
@ -667,8 +686,12 @@ public class TypeParser implements ISourceElementRequestor {
ITypeInfo info = fTypeCache.getType(type, qualifiedName);
if (info == null || info.isUndefinedType()) {
// add new type to cache
info = new TypeInfo(type, qualifiedName);
fTypeCache.insert(info);
if (info != null) {
info.setCElementType(type);
} else {
info = new TypeInfo(type, qualifiedName);
fTypeCache.insert(info);
}
TypeReference location;
if (originalRef instanceof IWorkingCopy) {
@ -696,10 +719,6 @@ public class TypeParser implements ISourceElementRequestor {
location = new TypeReference(path, fProject, offset, length);
}
info.addReference(location);
if (fTypeToFind != null && fTypeToFind.equals(info)) {
fFoundType = true;
}
}
/* (non-Javadoc)

View file

@ -13,6 +13,7 @@ package org.eclipse.cdt.internal.core.browser.util;
import java.io.File;
import java.io.IOException;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
@ -70,10 +71,26 @@ public class PathUtil {
return fullPath;
}
public static IPath getProjectRelativePath(IPath fullPath, IProject project) {
IPath projectPath = project.getFullPath();
if (projectPath.isPrefixOf(fullPath)) {
return fullPath.removeFirstSegments(projectPath.segmentCount());
}
projectPath = project.getLocation();
if (projectPath.isPrefixOf(fullPath)) {
return fullPath.removeFirstSegments(projectPath.segmentCount());
}
return getWorkspaceRelativePath(fullPath);
}
public static IPath getWorkspaceRelativePath(String fullPath) {
return getWorkspaceRelativePath(new Path(fullPath));
}
public static IPath getProjectRelativePath(String fullPath, IProject project) {
return getProjectRelativePath(new Path(fullPath), project);
}
public static IPath getRawLocation(IPath wsRelativePath) {
IWorkspaceRoot workspaceRoot = getWorkspaceRoot();
if (workspaceRoot != null && wsRelativePath != null) {

View file

@ -31,6 +31,10 @@ public class SimpleStack {
items = new ArrayList(initialSize);
}
public void clear() {
items.clear();
}
public Object push(Object item) {
items.add(item);
if (VERBOSE)