Merge remote-tracking branch 'origin/GP-3084_Dan_hopTraceEventQueueForViews--SQUASHED'

This commit is contained in:
Ryan Kurtz 2023-02-09 09:39:29 -05:00
commit 37a0873dc6
6 changed files with 250 additions and 176 deletions

View file

@ -26,6 +26,7 @@ import com.google.common.cache.RemovalNotification;
import db.DBHandle;
import generic.depends.DependentService;
import generic.depends.err.ServiceConstructionException;
import ghidra.framework.model.DomainObjectChangeRecord;
import ghidra.framework.options.Options;
import ghidra.lifecycle.Internal;
import ghidra.program.model.address.*;
@ -140,6 +141,8 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
protected boolean recordChanges = false;
protected Set<DBTraceTimeViewport> viewports = new WeakHashCowSet<>();
protected ListenerSet<DBTraceDirectChangeListener> directListeners =
new ListenerSet<>(DBTraceDirectChangeListener.class);
protected DBTraceVariableSnapProgramView programView;
protected Set<DBTraceVariableSnapProgramView> programViews = new WeakHashCowSet<>();
protected Set<TraceProgramView> programViewsView = Collections.unmodifiableSet(programViews);
@ -586,6 +589,23 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
fireEvent(event);
}
@Override
public void fireEvent(DomainObjectChangeRecord ev) {
super.fireEvent(ev);
if (directListeners != null) {
// Some events fire during construction
directListeners.fire.changed(ev);
}
}
public void addDirectChangeListener(DBTraceDirectChangeListener listener) {
directListeners.add(listener);
}
public void removeDirectChangeListener(DBTraceDirectChangeListener listener) {
directListeners.remove(listener);
}
@Override
public DBTraceProgramView getFixedProgramView(long snap) {
// NOTE: The new viewport will need to read from the time manager during init

View file

@ -0,0 +1,22 @@
/* ###
* 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 ghidra.trace.database;
import ghidra.framework.model.DomainObjectChangeRecord;
public interface DBTraceDirectChangeListener {
void changed(DomainObjectChangeRecord rec);
}

View file

@ -42,8 +42,7 @@ import ghidra.program.model.util.AddressSetPropertyMap;
import ghidra.program.model.util.PropertyMapManager;
import ghidra.program.util.ChangeManager;
import ghidra.program.util.ProgramChangeRecord;
import ghidra.trace.database.DBTrace;
import ghidra.trace.database.DBTraceTimeViewport;
import ghidra.trace.database.*;
import ghidra.trace.database.listing.DBTraceCodeSpace;
import ghidra.trace.database.listing.DBTraceDefinedUnitsView;
import ghidra.trace.database.memory.DBTraceMemorySpace;
@ -82,7 +81,8 @@ public class DBTraceProgramView implements TraceProgramView {
public static final int TIME_INTERVAL = 100;
public static final int BUF_SIZE = 1000;
protected class EventTranslator extends TraceDomainObjectListener {
protected class EventTranslator extends TypedEventDispatcher
implements DBTraceDirectChangeListener {
public EventTranslator() {
listenForUntyped(DomainObject.DO_OBJECT_SAVED, this::eventPassthrough);
listenForUntyped(DomainObject.DO_DOMAIN_FILE_CHANGED, this::eventPassthrough);
@ -172,6 +172,11 @@ public class DBTraceProgramView implements TraceProgramView {
listenFor(TraceSymbolChangeType.DELETED, this::symbolDeleted);
}
@Override
public void changed(DomainObjectChangeRecord event) {
handleChangeRecord(event);
}
private void eventPassthrough(DomainObjectChangeRecord rec) {
fireEventAllViews(rec);
}
@ -1376,7 +1381,7 @@ public class DBTraceProgramView implements TraceProgramView {
protected synchronized EventTranslator getEventTranslator() {
if (eventTranslator == null) {
eventTranslator = new EventTranslator();
trace.addListener(eventTranslator);
trace.addDirectChangeListener(eventTranslator);
}
return eventTranslator;
}

View file

@ -15,165 +15,12 @@
*/
package ghidra.trace.model;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import ghidra.framework.model.*;
import ghidra.trace.util.*;
import ghidra.util.TimedMsg;
public class TraceDomainObjectListener implements DomainObjectListener {
public class TraceDomainObjectListener extends TypedEventDispatcher
implements DomainObjectListener {
public interface EventRecordHandler<T, U> {
void handle(TraceChangeRecord<T, U> record);
}
public interface FullEventRecordHandler<T, U> extends EventRecordHandler<T, U> {
void handle(TraceAddressSpace space, T affectedObject, U oldValue, U newValue);
@Override
default void handle(TraceChangeRecord<T, U> record) {
handle(record.getSpace(), record.getAffectedObject(), record.getOldValue(),
record.getNewValue());
}
}
public interface AffectedObjectHandler<T> extends EventRecordHandler<T, Void> {
void handle(TraceAddressSpace space, T affectedObject);
@Override
default void handle(TraceChangeRecord<T, Void> record) {
handle(record.getSpace(), record.getAffectedObject());
}
}
public interface AffectedObjectOnlyHandler<T> extends EventRecordHandler<T, Void> {
void handle(T affectedObject);
@Override
default void handle(TraceChangeRecord<T, Void> record) {
handle(record.getAffectedObject());
}
}
public interface AffectedAndValuesOnlyHandler<T, U> extends EventRecordHandler<T, U> {
void handle(T affectedObject, U oldValue, U newValue);
@Override
default void handle(TraceChangeRecord<T, U> record) {
handle(record.getAffectedObject(), record.getOldValue(), record.getNewValue());
}
}
public interface SpaceValuesHandler<U> extends EventRecordHandler<Void, U> {
void handle(TraceAddressSpace space, U oldValue, U newValue);
@Override
default void handle(TraceChangeRecord<Void, U> record) {
handle(record.getSpace(), record.getOldValue(), record.getNewValue());
}
}
public interface ValuesOnlyHandler<U> extends EventRecordHandler<Void, U> {
void handle(U oldValue, U newValue);
@Override
default void handle(TraceChangeRecord<Void, U> record) {
handle(record.getOldValue(), record.getNewValue());
}
}
public interface IgnoreValuesHandler extends EventRecordHandler<Object, Object> {
void handle(TraceAddressSpace space);
@Override
default void handle(TraceChangeRecord<Object, Object> record) {
handle(record.getSpace());
}
}
public interface IgnoreAllHandler extends EventRecordHandler<Object, Object> {
void handle();
@Override
default void handle(TraceChangeRecord<Object, Object> record) {
handle();
}
}
private Map<TraceChangeType<?, ?>, EventRecordHandler<?, ?>> typedMap = new HashMap<>();
private Map<Integer, Consumer<DomainObjectChangeRecord>> untypedMap = new HashMap<>();
private Consumer<DomainObjectChangeRecord> restoredHandler = null;
protected <T, U> void listenFor(TraceChangeType<T, U> type, EventRecordHandler<T, U> handler) {
typedMap.put(type, handler);
}
protected <T, U> void listenFor(TraceChangeType<T, U> type,
FullEventRecordHandler<? super T, ? super U> handler) {
typedMap.put(type, handler);
}
protected <T, U> void listenFor(TraceChangeType<T, U> type,
AffectedObjectHandler<? super T> handler) {
typedMap.put(type, handler);
}
protected <T, U> void listenFor(TraceChangeType<T, U> type,
AffectedObjectOnlyHandler<? super T> handler) {
typedMap.put(type, handler);
}
/**
* Listen for the given event, taking the affected object, the old value, and the new value
*
* @param <T> the type of the affected object
* @param <U> the type of the values
* @param type the event type
* @param handler the handler
*/
protected <T, U> void listenFor(TraceChangeType<T, U> type,
AffectedAndValuesOnlyHandler<? super T, ? super U> handler) {
typedMap.put(type, handler);
}
protected <T, U> void listenFor(TraceChangeType<T, U> type,
ValuesOnlyHandler<? super U> handler) {
typedMap.put(type, handler);
}
protected <T, U> void listenFor(TraceChangeType<T, U> type,
SpaceValuesHandler<? super U> handler) {
typedMap.put(type, handler);
}
protected void listenFor(TraceChangeType<?, ?> type, IgnoreValuesHandler handler) {
typedMap.put(type, handler);
}
protected void listenFor(TraceChangeType<?, ?> type, IgnoreAllHandler handler) {
typedMap.put(type, handler);
}
protected void listenForUntyped(int type, Consumer<DomainObjectChangeRecord> handler) {
if (type == DomainObject.DO_OBJECT_RESTORED) {
restoredHandler = handler;
}
else {
untypedMap.put(type, handler);
}
}
@SuppressWarnings("unchecked")
public void handleTraceChangeRecord(TraceChangeRecord<?,?> rec) {
@SuppressWarnings("rawtypes")
EventRecordHandler handler = typedMap.get(rec.getType());
if (handler != null) {
handler.handle(rec);
}
}
@Override
public void domainObjectChanged(DomainObjectChangedEvent ev) {
//TimedMsg.info(this, "Handing (" + this + "): " + ev);
@ -189,23 +36,8 @@ public class TraceDomainObjectListener implements DomainObjectListener {
}
//Map<String, Integer> CountsByType = new TreeMap<>();
for (DomainObjectChangeRecord rec : ev) {
//String typeName = DefaultTraceChangeType.getName(rec.getEventType());
//CountsByType.compute(typeName, (k, v) -> v == null ? 1 : v + 1);
if (rec instanceof TraceChangeRecord) {
handleTraceChangeRecord((TraceChangeRecord<?, ?>) rec);
continue;
}
Consumer<DomainObjectChangeRecord> handler;
if (null != (handler = untypedMap.get(rec.getEventType()))) {
handler.accept(rec);
continue;
}
unhandled(rec);
handleChangeRecord(rec);
}
//TimedMsg.info(this, " Done: " + CountsByType);
}
protected void unhandled(DomainObjectChangeRecord rec) {
// Extension point
}
}

View file

@ -0,0 +1,195 @@
/* ###
* 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 ghidra.trace.model;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import ghidra.framework.model.DomainObject;
import ghidra.framework.model.DomainObjectChangeRecord;
import ghidra.trace.util.*;
public class TypedEventDispatcher {
public interface EventRecordHandler<T, U> {
void handle(TraceChangeRecord<T, U> record);
}
public interface FullEventRecordHandler<T, U> extends EventRecordHandler<T, U> {
void handle(TraceAddressSpace space, T affectedObject, U oldValue, U newValue);
@Override
default void handle(TraceChangeRecord<T, U> record) {
handle(record.getSpace(), record.getAffectedObject(), record.getOldValue(),
record.getNewValue());
}
}
public interface AffectedObjectHandler<T> extends EventRecordHandler<T, Void> {
void handle(TraceAddressSpace space, T affectedObject);
@Override
default void handle(TraceChangeRecord<T, Void> record) {
handle(record.getSpace(), record.getAffectedObject());
}
}
public interface AffectedObjectOnlyHandler<T> extends EventRecordHandler<T, Void> {
void handle(T affectedObject);
@Override
default void handle(TraceChangeRecord<T, Void> record) {
handle(record.getAffectedObject());
}
}
public interface AffectedAndValuesOnlyHandler<T, U> extends EventRecordHandler<T, U> {
void handle(T affectedObject, U oldValue, U newValue);
@Override
default void handle(TraceChangeRecord<T, U> record) {
handle(record.getAffectedObject(), record.getOldValue(), record.getNewValue());
}
}
public interface SpaceValuesHandler<U> extends EventRecordHandler<Void, U> {
void handle(TraceAddressSpace space, U oldValue, U newValue);
@Override
default void handle(TraceChangeRecord<Void, U> record) {
handle(record.getSpace(), record.getOldValue(), record.getNewValue());
}
}
public interface ValuesOnlyHandler<U> extends EventRecordHandler<Void, U> {
void handle(U oldValue, U newValue);
@Override
default void handle(TraceChangeRecord<Void, U> record) {
handle(record.getOldValue(), record.getNewValue());
}
}
public interface IgnoreValuesHandler extends EventRecordHandler<Object, Object> {
void handle(TraceAddressSpace space);
@Override
default void handle(TraceChangeRecord<Object, Object> record) {
handle(record.getSpace());
}
}
public interface IgnoreAllHandler extends EventRecordHandler<Object, Object> {
void handle();
@Override
default void handle(TraceChangeRecord<Object, Object> record) {
handle();
}
}
private Map<TraceChangeType<?, ?>, EventRecordHandler<?, ?>> typedMap = new HashMap<>();
private Map<Integer, Consumer<DomainObjectChangeRecord>> untypedMap = new HashMap<>();
protected Consumer<DomainObjectChangeRecord> restoredHandler = null;
protected <T, U> void listenFor(TraceChangeType<T, U> type, EventRecordHandler<T, U> handler) {
typedMap.put(type, handler);
}
protected <T, U> void listenFor(TraceChangeType<T, U> type,
FullEventRecordHandler<? super T, ? super U> handler) {
typedMap.put(type, handler);
}
protected <T, U> void listenFor(TraceChangeType<T, U> type,
AffectedObjectHandler<? super T> handler) {
typedMap.put(type, handler);
}
protected <T, U> void listenFor(TraceChangeType<T, U> type,
AffectedObjectOnlyHandler<? super T> handler) {
typedMap.put(type, handler);
}
/**
* Listen for the given event, taking the affected object, the old value, and the new value
*
* @param <T> the type of the affected object
* @param <U> the type of the values
* @param type the event type
* @param handler the handler
*/
protected <T, U> void listenFor(TraceChangeType<T, U> type,
AffectedAndValuesOnlyHandler<? super T, ? super U> handler) {
typedMap.put(type, handler);
}
protected <T, U> void listenFor(TraceChangeType<T, U> type,
ValuesOnlyHandler<? super U> handler) {
typedMap.put(type, handler);
}
protected <T, U> void listenFor(TraceChangeType<T, U> type,
SpaceValuesHandler<? super U> handler) {
typedMap.put(type, handler);
}
protected void listenFor(TraceChangeType<?, ?> type, IgnoreValuesHandler handler) {
typedMap.put(type, handler);
}
protected void listenFor(TraceChangeType<?, ?> type, IgnoreAllHandler handler) {
typedMap.put(type, handler);
}
protected void listenForUntyped(int type, Consumer<DomainObjectChangeRecord> handler) {
if (type == DomainObject.DO_OBJECT_RESTORED) {
restoredHandler = handler;
}
else {
untypedMap.put(type, handler);
}
}
public void handleChangeRecord(DomainObjectChangeRecord rec) {
//String typeName = DefaultTraceChangeType.getName(rec.getEventType());
//CountsByType.compute(typeName, (k, v) -> v == null ? 1 : v + 1);
if (rec instanceof TraceChangeRecord) {
handleTraceChangeRecord((TraceChangeRecord<?, ?>) rec);
return;
}
Consumer<DomainObjectChangeRecord> handler;
if (null != (handler = untypedMap.get(rec.getEventType()))) {
handler.accept(rec);
return;
}
unhandled(rec);
}
@SuppressWarnings("unchecked")
public void handleTraceChangeRecord(TraceChangeRecord<?, ?> rec) {
@SuppressWarnings("rawtypes")
EventRecordHandler handler = typedMap.get(rec.getType());
if (handler != null) {
handler.handle(rec);
}
}
protected void unhandled(DomainObjectChangeRecord rec) {
// Extension point
}
}