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:
parent
24f099f882
commit
1af8428deb
8 changed files with 168 additions and 15 deletions
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue