1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-09 17:25:38 +02:00

Bug 509898 - CPPSemantics.isReachableFromAst is slow and is causing UI

freezes

Optimized IndexFileSet.containsDeclaration method for performance and to
reduce its memory footprint.

Change-Id: I0e867b96c6d6ab102561bc999127980d1be26a7b
This commit is contained in:
Sergey Prigogin 2017-01-18 19:57:44 -08:00
parent 24f099f882
commit 1af8428deb
8 changed files with 168 additions and 15 deletions

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2008, 2012 Wind River Systems, Inc. and others. * Copyright (c) 2008, 2017 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -7,6 +7,7 @@
* *
* Contributors: * Contributors:
* Markus Schorn - initial API and implementation * Markus Schorn - initial API and implementation
* Sergey Prigogin (Google)
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.core.index; package org.eclipse.cdt.internal.core.index;
@ -15,7 +16,6 @@ import org.eclipse.core.runtime.CoreException;
public interface IIndexFragmentFileSet { public interface IIndexFragmentFileSet {
/** /**
* Returns whether the file-set contains the file of the local binding. * Returns whether the file-set contains the file of the local binding.
* @throws CoreException
*/ */
boolean containsFileOfLocalBinding(IIndexFragmentBinding binding) throws CoreException; boolean containsFileOfLocalBinding(IIndexFragmentBinding binding) throws CoreException;
@ -33,4 +33,9 @@ public interface IIndexFragmentFileSet {
* Returns whether the file set contains the given file. * Returns whether the file set contains the given file.
*/ */
boolean contains(IIndexFragmentFile file) throws CoreException; boolean contains(IIndexFragmentFile file) throws CoreException;
/**
* Returns {@code true} if this file set is empty.
*/
boolean isEmpty();
} }

View file

@ -21,6 +21,11 @@ import org.eclipse.cdt.core.index.IIndexBinding;
import org.eclipse.cdt.core.index.IIndexFile; import org.eclipse.cdt.core.index.IIndexFile;
import org.eclipse.cdt.core.index.IIndexFileLocation; import org.eclipse.cdt.core.index.IIndexFileLocation;
import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.cdt.core.index.IIndexFileSet;
import org.eclipse.cdt.internal.core.pdom.PDOM;
import org.eclipse.cdt.internal.core.pdom.PDOMFileSet;
import org.eclipse.cdt.internal.core.pdom.db.Database;
import org.eclipse.cdt.internal.core.pdom.dom.IRecordIterator;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMName;
import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
@ -45,26 +50,30 @@ public class IndexFileSet implements IIndexFileSet {
@Override @Override
public void remove(IIndexFile indexFile) { public void remove(IIndexFile indexFile) {
final IIndexFragmentFile fragFile = (IIndexFragmentFile) indexFile; final IIndexFragmentFile fragmentFile = (IIndexFragmentFile) indexFile;
final IIndexFragment frag= fragFile.getIndexFragment(); final IIndexFragment fragment = fragmentFile.getIndexFragment();
IIndexFragmentFileSet subSet= fSubSets.get(frag); IIndexFragmentFileSet subSet = fSubSets.get(fragment);
if (subSet != null) { if (subSet != null) {
subSet.remove(fragFile); subSet.remove(fragmentFile);
} }
} }
@Override @Override
public boolean containsDeclaration(IIndexBinding binding) { public boolean containsDeclaration(IIndexBinding binding) {
for (Map.Entry<IIndexFragment, IIndexFragmentFileSet> entry : fSubSets.entrySet()) { for (Map.Entry<IIndexFragment, IIndexFragmentFileSet> entry : fSubSets.entrySet()) {
IIndexFragment fragment = entry.getKey();
IIndexFragmentFileSet fragmentFileSet = entry.getValue();
try { try {
IIndexFragmentName[] names = if (!fragmentFileSet.isEmpty() && fragmentFileSet instanceof PDOMFileSet && fragment instanceof PDOM) {
entry.getKey().findNames(binding, IIndexFragment.FIND_DECLARATIONS_DEFINITIONS); PDOM pdom = (PDOM) fragment;
for (IIndexFragmentName name : names) { PDOMFileSet pdomFileSet = (PDOMFileSet) fragmentFileSet;
try { Database db = pdom.getDB();
if (entry.getValue().contains((IIndexFragmentFile) name.getFile())) IRecordIterator nameIterator = pdom.getDeclarationsDefintitionsRecordIterator(binding);
long nameRecord;
while ((nameRecord = nameIterator.next()) != 0) {
long fileRecord = PDOMName.getFileRecord(db, nameRecord);
if (pdomFileSet.containsFile(fileRecord))
return true; return true;
} catch (CoreException e) {
CCorePlugin.log(e);
} }
} }
} catch (CoreException e) { } catch (CoreException e) {

View file

@ -77,9 +77,11 @@ import org.eclipse.cdt.internal.core.pdom.db.Database;
import org.eclipse.cdt.internal.core.pdom.db.IBTreeComparator; import org.eclipse.cdt.internal.core.pdom.db.IBTreeComparator;
import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor; import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor;
import org.eclipse.cdt.internal.core.pdom.dom.BindingCollector; import org.eclipse.cdt.internal.core.pdom.dom.BindingCollector;
import org.eclipse.cdt.internal.core.pdom.dom.CompoundRecordIterator;
import org.eclipse.cdt.internal.core.pdom.dom.FindBinding; import org.eclipse.cdt.internal.core.pdom.dom.FindBinding;
import org.eclipse.cdt.internal.core.pdom.dom.IPDOMIterator; import org.eclipse.cdt.internal.core.pdom.dom.IPDOMIterator;
import org.eclipse.cdt.internal.core.pdom.dom.IPDOMLinkageFactory; import org.eclipse.cdt.internal.core.pdom.dom.IPDOMLinkageFactory;
import org.eclipse.cdt.internal.core.pdom.dom.IRecordIterator;
import org.eclipse.cdt.internal.core.pdom.dom.MacroContainerCollector; import org.eclipse.cdt.internal.core.pdom.dom.MacroContainerCollector;
import org.eclipse.cdt.internal.core.pdom.dom.MacroContainerPatternCollector; import org.eclipse.cdt.internal.core.pdom.dom.MacroContainerPatternCollector;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding;
@ -1270,6 +1272,16 @@ public class PDOM extends PlatformObject implements IPDOM {
} }
} }
public IRecordIterator getDeclarationsDefintitionsRecordIterator(IIndexBinding binding) throws CoreException {
IIndexFragmentBinding myBinding= adaptBinding(binding);
if (myBinding instanceof PDOMBinding) {
PDOMBinding pdomBinding = (PDOMBinding) myBinding;
return new CompoundRecordIterator(pdomBinding.getDeclarationRecordIterator(),
pdomBinding.getDefinitionRecordIterator());
}
return IRecordIterator.EMPTY;
}
protected boolean isCommitted(PDOMName name) throws CoreException { protected boolean isCommitted(PDOMName name) throws CoreException {
return true; return true;
} }

View file

@ -19,7 +19,7 @@ import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMFile; import org.eclipse.cdt.internal.core.pdom.dom.PDOMFile;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
public class PDOMFileSet implements IIndexFragmentFileSet { public final class PDOMFileSet implements IIndexFragmentFileSet {
private final HashSet<Long> fFileIDs= new HashSet<>(); private final HashSet<Long> fFileIDs= new HashSet<>();
@Override @Override
@ -50,4 +50,16 @@ public class PDOMFileSet implements IIndexFragmentFileSet {
} }
return false; return false;
} }
/**
* Returns whether the file set contains the file corresponding to the given record.
*/
public boolean containsFile(long fileRecord) {
return fFileIDs.contains(fileRecord);
}
@Override
public boolean isEmpty() {
return fFileIDs.isEmpty();
}
} }

View file

@ -0,0 +1,43 @@
/*******************************************************************************
* Copyright (c) 2017 Google, Inc and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Sergey Prigogin (Google) - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.dom;
import org.eclipse.core.runtime.CoreException;
/**
* A record iterator that is a concatenation of multiple record iterators.
*/
public final class CompoundRecordIterator implements IRecordIterator {
private final IRecordIterator[] iterators;
private int currentOffset;
/**
* Initializes the compound iterator.
*
* @param iterators the iterators to concatenate
*/
public CompoundRecordIterator(IRecordIterator... iterators) {
if (iterators == null)
throw new NullPointerException();
this.iterators = iterators;
}
@Override
public long next() throws CoreException {
for (; currentOffset < iterators.length; currentOffset++) {
IRecordIterator iterator = iterators[currentOffset];
long record = iterator.next();
if (record != 0)
return record;
}
return 0;
}
}

View file

@ -0,0 +1,27 @@
/*******************************************************************************
* Copyright (c) 2017 Google, Inc and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Sergey Prigogin (Google) - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.dom;
import org.eclipse.core.runtime.CoreException;
/**
* An interface for iterating through lists that are stored in the PDOM without instantiating objects.
*/
@FunctionalInterface
public interface IRecordIterator {
public static final IRecordIterator EMPTY = () -> 0;
/**
* Returns the record of next element in the iteration, or zero if there are no elements left in
* the iteration.
*/
public long next() throws CoreException;
}

View file

@ -175,6 +175,16 @@ public abstract class PDOMBinding extends PDOMNamedNode implements IPDOMBinding
return namerec != 0 ? new PDOMName(getLinkage(), namerec) : null; return namerec != 0 ? new PDOMName(getLinkage(), namerec) : null;
} }
public IRecordIterator getDeclarationRecordIterator() throws CoreException {
Database db = getDB();
return PDOMName.getNameInBindingRecordIterator(db, db.getRecPtr(record + FIRST_DECL));
}
public IRecordIterator getDefinitionRecordIterator() throws CoreException {
Database db = getDB();
return PDOMName.getNameInBindingRecordIterator(db, db.getRecPtr(record + FIRST_DEF));
}
/** /**
* Returns an iterator over the names in other linkages that reference this binding. Does * Returns an iterator over the names in other linkages that reference this binding. Does
* not return null. * not return null.

View file

@ -195,6 +195,10 @@ public final class PDOMName implements IIndexFragmentName, IASTFileLocation {
linkage.getDB().putRecPtr(record + FILE_REC_OFFSET, file != null ? file.getRecord() : 0); linkage.getDB().putRecPtr(record + FILE_REC_OFFSET, file != null ? file.getRecord() : 0);
} }
public static long getFileRecord(Database db, long record) throws CoreException {
return db.getRecPtr(record + FILE_REC_OFFSET);
}
@Override @Override
public IIndexName getEnclosingDefinition() throws CoreException { public IIndexName getEnclosingDefinition() throws CoreException {
long namerec = getEnclosingDefinitionRecord(); long namerec = getEnclosingDefinitionRecord();
@ -419,7 +423,7 @@ public final class PDOMName implements IIndexFragmentName, IASTFileLocation {
@Override @Override
public IIndexName[] getEnclosedNames() throws CoreException { public IIndexName[] getEnclosedNames() throws CoreException {
ArrayList<PDOMName> result= new ArrayList<PDOMName>(); ArrayList<PDOMName> result= new ArrayList<>();
PDOMName name= getNextInFile(); PDOMName name= getNextInFile();
while (name != null) { while (name != null) {
if (name.getEnclosingDefinitionRecord() == record) { if (name.getEnclosingDefinitionRecord() == record) {
@ -429,4 +433,35 @@ public final class PDOMName implements IIndexFragmentName, IASTFileLocation {
} }
return result.toArray(new PDOMName[result.size()]); return result.toArray(new PDOMName[result.size()]);
} }
/**
* Returns an iterator over names in binding. This is a lighter weight alternative to
* the {@link #getNextInBinding()} method.
*/
public static IRecordIterator getNameInBindingRecordIterator(Database db, long nameRecord) {
if (nameRecord == 0)
return IRecordIterator.EMPTY;
return new NameInBindingRecordIterator(db, nameRecord);
}
/**
* Iterator over PDOMName records in a binding.
*/
private static class NameInBindingRecordIterator implements IRecordIterator {
final Database db;
long nameRecord;
public NameInBindingRecordIterator(Database db, long nameRecord) {
this.db = db;
this.nameRecord = nameRecord;
}
@Override
public long next() throws CoreException {
long record = nameRecord;
if (record != 0)
nameRecord = db.getRecPtr(record + BINDING_NEXT_OFFSET);
return record;
}
}
} }