GT-3226 - Symbol Table - Performance improvements - review fixes:

removed odd comparator name/structure; update ProgramSymbol context to
use Symbols and not IDs
This commit is contained in:
dragonmacher
2019-10-28 16:06:26 -04:00
parent 9e320c6401
commit 26cdfd47d7
12 changed files with 64 additions and 164 deletions
@@ -16,80 +16,34 @@
package ghidra.app.context; package ghidra.app.context;
import java.awt.Component; import java.awt.Component;
import java.util.Iterator; import java.util.*;
import java.util.NoSuchElementException;
import docking.ComponentProvider; import docking.ComponentProvider;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.Symbol; import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolIterator;
public class ProgramSymbolActionContext extends ProgramActionContext { public class ProgramSymbolActionContext extends ProgramActionContext {
private final long[] symbolIDs; private List<Symbol> symbols = new ArrayList<Symbol>();
public ProgramSymbolActionContext(ComponentProvider provider, Program program, long[] symbolIDs, public ProgramSymbolActionContext(ComponentProvider provider, Program program,
Component sourceComponent) { List<Symbol> symbols, Component sourceComponent) {
super(provider, program, sourceComponent); super(provider, program, sourceComponent);
this.symbolIDs = symbolIDs; this.symbols = symbols == null ? Collections.emptyList() : symbols;
} }
public int getSymbolCount() { public int getSymbolCount() {
return symbolIDs != null ? symbolIDs.length : 0; return symbols.size();
} }
public Symbol getFirstSymbol() { public Symbol getFirstSymbol() {
if (symbolIDs == null || symbolIDs.length == 0) { if (symbols.isEmpty()) {
return null; return null;
} }
return program.getSymbolTable().getSymbol(symbolIDs[0]); return symbols.get(0);
} }
public SymbolIterator getSymbols() { public Iterable<Symbol> getSymbols() {
return new MySymbolIterator(); return symbols;
}
private class MySymbolIterator implements SymbolIterator {
private int index = -1;
private Symbol symbol = null;
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public Iterator<Symbol> iterator() {
return this;
}
@Override
public boolean hasNext() {
if (symbol != null) {
return true;
}
if (symbolIDs == null) {
return false;
}
while (index < (symbolIDs.length - 1)) {
symbol = program.getSymbolTable().getSymbol(symbolIDs[++index]);
if (symbol != null) {
return true;
}
}
return false;
}
@Override
public Symbol next() {
if (hasNext()) {
Symbol s = symbol;
symbol = null;
return s;
}
throw new NoSuchElementException();
}
} }
} }
@@ -20,11 +20,9 @@ import ghidra.program.model.listing.Function;
class FunctionRowObject implements Comparable<FunctionRowObject> { class FunctionRowObject implements Comparable<FunctionRowObject> {
private final Function function; private final Function function;
private final long key;
FunctionRowObject(Function function) { FunctionRowObject(Function function) {
this.function = function; this.function = function;
this.key = function.getID();
} }
Function getFunction() { Function getFunction() {
@@ -33,10 +31,7 @@ class FunctionRowObject implements Comparable<FunctionRowObject> {
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; return (int) function.getID();
int result = 1;
result = prime * result + (int) (key ^ (key >>> 32));
return result;
} }
@Override @Override
@@ -50,19 +45,21 @@ class FunctionRowObject implements Comparable<FunctionRowObject> {
if (getClass() != obj.getClass()) { if (getClass() != obj.getClass()) {
return false; return false;
} }
long key = function.getID();
FunctionRowObject other = (FunctionRowObject) obj; FunctionRowObject other = (FunctionRowObject) obj;
if (key != other.key) { if (key != other.function.getID()) {
return false; return false;
} }
return true; return true;
} }
long getKey() { long getKey() {
return key; return function.getID();
} }
@Override @Override
public int compareTo(FunctionRowObject o) { public int compareTo(FunctionRowObject o) {
return ((Long) key).compareTo(o.key); return ((Long) function.getID()).compareTo(o.function.getID());
} }
} }
@@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,11 +15,15 @@
*/ */
package ghidra.app.plugin.core.symboltree; package ghidra.app.plugin.core.symboltree;
import java.util.ArrayList;
import java.util.List;
import javax.swing.tree.TreePath;
import ghidra.app.context.ProgramSymbolActionContext; import ghidra.app.context.ProgramSymbolActionContext;
import ghidra.app.plugin.core.symboltree.nodes.SymbolNode; import ghidra.app.plugin.core.symboltree.nodes.SymbolNode;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.Symbol;
import javax.swing.tree.TreePath;
public class SymbolTreeActionContext extends ProgramSymbolActionContext { public class SymbolTreeActionContext extends ProgramSymbolActionContext {
@@ -28,7 +31,7 @@ public class SymbolTreeActionContext extends ProgramSymbolActionContext {
SymbolTreeActionContext(SymbolTreeProvider provider, Program program, SymbolGTree tree, SymbolTreeActionContext(SymbolTreeProvider provider, Program program, SymbolGTree tree,
TreePath[] selectionPaths) { TreePath[] selectionPaths) {
super(provider, program, getSymbolIDs(selectionPaths), tree); super(provider, program, getSymbols(selectionPaths), tree);
this.selectionPaths = selectionPaths; this.selectionPaths = selectionPaths;
} }
@@ -51,23 +54,23 @@ public class SymbolTreeActionContext extends ProgramSymbolActionContext {
return null; return null;
} }
private static long[] getSymbolIDs(TreePath[] selectionPaths) { private static List<Symbol> getSymbols(TreePath[] selectionPaths) {
if (selectionPaths == null) { if (selectionPaths == null) {
return null; return null;
} }
long[] symbolIDs = new long[selectionPaths.length];
int index = 0; List<Symbol> symbols = new ArrayList<>();
for (TreePath treePath : selectionPaths) { for (TreePath treePath : selectionPaths) {
Object object = treePath.getLastPathComponent(); Object object = treePath.getLastPathComponent();
if (object instanceof SymbolNode) { if (object instanceof SymbolNode) {
SymbolNode symbolNode = (SymbolNode) object; SymbolNode symbolNode = (SymbolNode) object;
symbolIDs[index++] = symbolNode.getSymbolID(); symbols.add(symbolNode.getSymbol());
} }
else { else {
// Do not return symbols if selection contains non-symbolNodes // Do not return symbols if selection contains non-symbolNodes
return null; return null;
} }
} }
return symbolIDs; return symbols;
} }
} }
@@ -185,7 +185,7 @@ class SymbolPanel extends JPanel {
return symTable.getRowCount(); return symTable.getRowCount();
} }
List<Symbol> getSelectedSymbolKeys() { List<Symbol> getSelectedSymbols() {
int[] rows = symTable.getSelectedRows(); int[] rows = symTable.getSelectedRows();
return tableModel.getRowObjects(rows); return tableModel.getRowObjects(rows);
} }
@@ -75,17 +75,12 @@ class SymbolProvider extends ComponentProviderAdapter {
return null; return null;
} }
List<Symbol> rowObjects = symbolPanel.getSelectedSymbolKeys(); List<Symbol> symbols = symbolPanel.getSelectedSymbols();
long[] symbolIDs = new long[rowObjects.size()]; return new ProgramSymbolActionContext(this, program, symbols, getTable());
int index = 0;
for (Symbol obj : rowObjects) {
symbolIDs[index++] = obj.getID();
}
return new ProgramSymbolActionContext(this, program, symbolIDs, getTable());
} }
void deleteSymbols() { void deleteSymbols() {
List<Symbol> rowObjects = symbolPanel.getSelectedSymbolKeys(); List<Symbol> rowObjects = symbolPanel.getSelectedSymbols();
symbolKeyModel.delete(rowObjects); symbolKeyModel.delete(rowObjects);
} }
@@ -94,7 +89,7 @@ class SymbolProvider extends ComponentProviderAdapter {
} }
Symbol getCurrentSymbol() { Symbol getCurrentSymbol() {
List<Symbol> rowObjects = symbolPanel.getSelectedSymbolKeys(); List<Symbol> rowObjects = symbolPanel.getSelectedSymbols();
if (rowObjects != null && rowObjects.size() >= 1) { if (rowObjects != null && rowObjects.size() >= 1) {
return rowObjects.get(0); return rowObjects.get(0);
} }
@@ -20,7 +20,8 @@ import java.util.*;
import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelEvent;
import javax.swing.table.TableModel; import javax.swing.table.TableModel;
import docking.widgets.table.sort.*; import docking.widgets.table.sort.DefaultColumnComparator;
import docking.widgets.table.sort.RowBasedColumnComparator;
import ghidra.util.Swing; import ghidra.util.Swing;
import ghidra.util.datastruct.WeakDataStructureFactory; import ghidra.util.datastruct.WeakDataStructureFactory;
import ghidra.util.datastruct.WeakSet; import ghidra.util.datastruct.WeakSet;
@@ -329,7 +330,7 @@ public abstract class AbstractSortedTableModel<T> extends AbstractGTableModel<T>
* @return the comparator * @return the comparator
*/ */
protected Comparator<T> createSortComparator(int columnIndex) { protected Comparator<T> createSortComparator(int columnIndex) {
return new RowToColumnComparator<>(this, columnIndex, new DefaultColumnComparator(), return new RowBasedColumnComparator<>(this, columnIndex, new DefaultColumnComparator(),
new StringBasedBackupRowToColumnComparator()); new StringBasedBackupRowToColumnComparator());
} }
@@ -469,11 +470,11 @@ public abstract class AbstractSortedTableModel<T> extends AbstractGTableModel<T>
} }
} }
private class StringBasedBackupRowToColumnComparator implements BackupColumnComparator<T> { private class StringBasedBackupRowToColumnComparator implements Comparator<Object> {
@Override @Override
public int compare(T t1, T t2, Object c1, Object c2) { public int compare(Object c1, Object c2) {
if (t1 == t2) { if (c1 == c2) {
return 0; return 0;
} }
@@ -178,11 +178,11 @@ public abstract class GDynamicColumnTableModel<ROW_TYPE, DATA_SOURCE>
Comparator<Object> columnComparator = createSortComparatorForColumn(columnIndex); Comparator<Object> columnComparator = createSortComparatorForColumn(columnIndex);
if (columnComparator != null) { if (columnComparator != null) {
// the given column has its own comparator; wrap and us that // the given column has its own comparator; wrap and us that
return new RowToColumnComparator<>(this, columnIndex, columnComparator); return new RowBasedColumnComparator<>(this, columnIndex, columnComparator);
} }
return new RowToColumnComparator<>(this, columnIndex, new DefaultColumnComparator(), return new RowBasedColumnComparator<>(this, columnIndex, new DefaultColumnComparator(),
new ColumnRenderedValueBackupRowComparator<>(this, columnIndex)); new ColumnRenderedValueBackupComparator<>(this, columnIndex));
} }
/** /**
@@ -1,50 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package docking.widgets.table.sort;
import java.util.Comparator;
/**
* An interface that is conceptually the same as a {@link Comparator}. The only difference is
* that we pass the row objects <b>and</b> the column values to
* {@link #compare(Object, Object, Object, Object)}. This allows us to take advantage of
* already-retrieved column values. This can speed-up table sorting, as repeatedly retrieving
* column values for each comparison is slow.
*
* @param <T> the row type
*/
public interface BackupColumnComparator<T> {
static final BackupColumnComparator<Object> NO_SORT_COMPARATOR = (t1, t2, o1, o2) -> 0;
@SuppressWarnings("unchecked") // we are casting to Object; safe since no comparisons are done
public static <T> BackupColumnComparator<T> getNoSortComparator() {
return (BackupColumnComparator<T>) NO_SORT_COMPARATOR;
}
/**
* Compares two row/column values using the same contract as
* {@link Comparator#compare(Object, Object)}
*
* @param t1 the 1st row object
* @param t2 the 2nd row object
* @param c1 the 1st column value
* @param c2 the second column value
* @return 0 if the 2 values compare the same; negative if the first value compares less than
* the second; positive if the first value compares as larger than the first
*/
public int compare(T t1, T t2, Object c1, Object c2);
}
@@ -15,6 +15,8 @@
*/ */
package docking.widgets.table.sort; package docking.widgets.table.sort;
import java.util.Comparator;
import docking.widgets.table.*; import docking.widgets.table.*;
import ghidra.docking.settings.Settings; import ghidra.docking.settings.Settings;
import ghidra.util.table.column.GColumnRenderer; import ghidra.util.table.column.GColumnRenderer;
@@ -27,7 +29,7 @@ import ghidra.util.table.column.GColumnRenderer.ColumnConstraintFilterMode;
* *
* @param <T> the row type * @param <T> the row type
*/ */
public class ColumnRenderedValueBackupRowComparator<T> implements BackupColumnComparator<T> { public class ColumnRenderedValueBackupComparator<T> implements Comparator<Object> {
protected int sortColumn; protected int sortColumn;
protected DynamicColumnTableModel<T> model; protected DynamicColumnTableModel<T> model;
@@ -36,7 +38,7 @@ public class ColumnRenderedValueBackupRowComparator<T> implements BackupColumnCo
// for column filtering only // for column filtering only
private boolean supportsColumnSorting = true; private boolean supportsColumnSorting = true;
public ColumnRenderedValueBackupRowComparator(DynamicColumnTableModel<T> model, public ColumnRenderedValueBackupComparator(DynamicColumnTableModel<T> model,
int sortColumn) { int sortColumn) {
this.model = model; this.model = model;
this.sortColumn = sortColumn; this.sortColumn = sortColumn;
@@ -54,8 +56,8 @@ public class ColumnRenderedValueBackupRowComparator<T> implements BackupColumnCo
} }
@Override @Override
public int compare(T t1, T t2, Object c1, Object c2) { public int compare(Object c1, Object c2) {
if (t1 == t2) { if (c1 == c2) {
return 0; return 0;
} }
@@ -27,13 +27,12 @@ import docking.widgets.table.TableComparators;
* *
* @param <T> the row type * @param <T> the row type
*/ */
public class RowToColumnComparator<T> implements Comparator<T> { public class RowBasedColumnComparator<T> implements Comparator<T> {
protected RowObjectTableModel<T> model; protected RowObjectTableModel<T> model;
protected int sortColumn; protected int sortColumn;
protected Comparator<Object> columnComparator; protected Comparator<Object> columnComparator;
protected BackupColumnComparator<T> backupRowComparator = protected Comparator<Object> backupRowComparator = TableComparators.getNoSortComparator();
BackupColumnComparator.getNoSortComparator();
/** /**
* Constructs this class with the given column comparator that will get called after the * Constructs this class with the given column comparator that will get called after the
@@ -43,7 +42,7 @@ public class RowToColumnComparator<T> implements Comparator<T> {
* @param sortColumn the column being sorted * @param sortColumn the column being sorted
* @param comparator the column comparator to use for sorting * @param comparator the column comparator to use for sorting
*/ */
public RowToColumnComparator(RowObjectTableModel<T> model, int sortColumn, public RowBasedColumnComparator(RowObjectTableModel<T> model, int sortColumn,
Comparator<Object> comparator) { Comparator<Object> comparator) {
this.model = model; this.model = model;
this.sortColumn = sortColumn; this.sortColumn = sortColumn;
@@ -60,8 +59,8 @@ public class RowToColumnComparator<T> implements Comparator<T> {
* @param comparator the column comparator to use for sorting * @param comparator the column comparator to use for sorting
* @param backupRowComparator the backup row comparator * @param backupRowComparator the backup row comparator
*/ */
public RowToColumnComparator(RowObjectTableModel<T> model, int sortColumn, public RowBasedColumnComparator(RowObjectTableModel<T> model, int sortColumn,
Comparator<Object> comparator, BackupColumnComparator<T> backupRowComparator) { Comparator<Object> comparator, Comparator<Object> backupRowComparator) {
this.model = model; this.model = model;
this.sortColumn = sortColumn; this.sortColumn = sortColumn;
this.columnComparator = Objects.requireNonNull(comparator); this.columnComparator = Objects.requireNonNull(comparator);
@@ -98,7 +97,7 @@ public class RowToColumnComparator<T> implements Comparator<T> {
// backup comparator is not a stub and will do something reasonable for the sort, // backup comparator is not a stub and will do something reasonable for the sort,
// depending upon how the model created this class. // depending upon how the model created this class.
// //
return backupRowComparator.compare(t1, t2, value1, value2); return backupRowComparator.compare(value1, value2);
} }
protected Object getColumnValue(T t) { protected Object getColumnValue(T t) {
@@ -15,16 +15,16 @@
*/ */
package docking.widgets.table.threaded; package docking.widgets.table.threaded;
import docking.widgets.table.sort.ColumnRenderedValueBackupRowComparator; import docking.widgets.table.sort.ColumnRenderedValueBackupComparator;
import docking.widgets.table.sort.RowToColumnComparator; import docking.widgets.table.sort.RowBasedColumnComparator;
/** /**
* A version of {@link ColumnRenderedValueBackupRowComparator} that uses the * A version of {@link ColumnRenderedValueBackupComparator} that uses the
* {@link ThreadedTableModel}'s cache for column lookups * {@link ThreadedTableModel}'s cache for column lookups
* *
* @param <T> the row type * @param <T> the row type
*/ */
public class ThreadedBackupRowComparator<T> extends ColumnRenderedValueBackupRowComparator<T> { public class ThreadedBackupRowComparator<T> extends ColumnRenderedValueBackupComparator<T> {
private ThreadedTableModel<T, ?> threadedModel; private ThreadedTableModel<T, ?> threadedModel;
@@ -34,7 +34,7 @@ public class ThreadedBackupRowComparator<T> extends ColumnRenderedValueBackupRow
* *
* @param model the table model using this comparator * @param model the table model using this comparator
* @param sortColumn the column being sorted * @param sortColumn the column being sorted
* @see RowToColumnComparator * @see RowBasedColumnComparator
*/ */
public ThreadedBackupRowComparator(ThreadedTableModel<T, ?> model, int sortColumn) { public ThreadedBackupRowComparator(ThreadedTableModel<T, ?> model, int sortColumn) {
super(model, sortColumn); super(model, sortColumn);
@@ -17,8 +17,7 @@ package docking.widgets.table.threaded;
import java.util.Comparator; import java.util.Comparator;
import docking.widgets.table.sort.BackupColumnComparator; import docking.widgets.table.sort.RowBasedColumnComparator;
import docking.widgets.table.sort.RowToColumnComparator;
/** /**
* A comparator for comparing table column values for threaded table models. This comparator * A comparator for comparing table column values for threaded table models. This comparator
@@ -26,7 +25,7 @@ import docking.widgets.table.sort.RowToColumnComparator;
* *
* @param <T> the row type * @param <T> the row type
*/ */
public class ThreadedTableColumnComparator<T> extends RowToColumnComparator<T> { public class ThreadedTableColumnComparator<T> extends RowBasedColumnComparator<T> {
private ThreadedTableModel<T, ?> threadedModel; private ThreadedTableModel<T, ?> threadedModel;
/** /**
@@ -36,7 +35,7 @@ public class ThreadedTableColumnComparator<T> extends RowToColumnComparator<T> {
* @param model the table model using this comparator * @param model the table model using this comparator
* @param sortColumn the column being sorted * @param sortColumn the column being sorted
* @param comparator the column comparator to use for sorting * @param comparator the column comparator to use for sorting
* @see RowToColumnComparator * @see RowBasedColumnComparator
*/ */
public ThreadedTableColumnComparator(ThreadedTableModel<T, ?> model, int sortColumn, public ThreadedTableColumnComparator(ThreadedTableModel<T, ?> model, int sortColumn,
Comparator<Object> comparator) { Comparator<Object> comparator) {
@@ -53,10 +52,10 @@ public class ThreadedTableColumnComparator<T> extends RowToColumnComparator<T> {
* @param sortColumn the column being sorted * @param sortColumn the column being sorted
* @param comparator the column comparator to use for sorting * @param comparator the column comparator to use for sorting
* @param backupRowComparator the backup row comparator * @param backupRowComparator the backup row comparator
* @see RowToColumnComparator * @see RowBasedColumnComparator
*/ */
public ThreadedTableColumnComparator(ThreadedTableModel<T, ?> model, int sortColumn, public ThreadedTableColumnComparator(ThreadedTableModel<T, ?> model, int sortColumn,
Comparator<Object> comparator, BackupColumnComparator<T> backupRowComparator) { Comparator<Object> comparator, Comparator<Object> backupRowComparator) {
super(model, sortColumn, comparator, backupRowComparator); super(model, sortColumn, comparator, backupRowComparator);
this.threadedModel = model; this.threadedModel = model;
} }