Skip to content

Commit

Permalink
Refactor InheritanceGraph, TransformationApplier to also not be tied …
Browse files Browse the repository at this point in the history
…directly to CDI
  • Loading branch information
Col-E committed Dec 6, 2024
1 parent 6788587 commit ed2d66e
Show file tree
Hide file tree
Showing 26 changed files with 396 additions and 165 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,14 @@
import software.coley.recaf.path.ClassPathNode;
import software.coley.recaf.path.PathNode;
import software.coley.recaf.services.inheritance.InheritanceGraph;
import software.coley.recaf.services.inheritance.InheritanceGraphService;
import software.coley.recaf.services.inheritance.InheritanceVertex;
import software.coley.recaf.util.JavaVersion;
import software.coley.recaf.workspace.model.Workspace;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.List;
import java.util.Objects;

/**
* JVM assembler pipeline implementation.
Expand All @@ -52,12 +53,12 @@ public class JvmAssemblerPipeline extends AbstractAssemblerPipeline<JvmClassInfo

@Inject
public JvmAssemblerPipeline(@Nonnull Workspace workspace,
@Nonnull InheritanceGraph inheritanceGraph,
@Nonnull AssemblerPipelineGeneralConfig generalConfig,
@Nonnull JvmAssemblerPipelineConfig config) {
@Nonnull InheritanceGraphService graphService,
@Nonnull AssemblerPipelineGeneralConfig generalConfig,
@Nonnull JvmAssemblerPipelineConfig config) {
super(generalConfig, config);
this.workspace = workspace;
this.inheritanceGraph = inheritanceGraph;
this.inheritanceGraph = Objects.requireNonNull(graphService.getCurrentWorkspaceInheritanceGraph(), "Graph not created");
}

@Nonnull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
*/
@EagerInitialization
@ApplicationScoped
public class CallGraphService implements Service, WorkspaceOpenListener, WorkspaceCloseListener {
public class CallGraphService implements Service {
public static final String SERVICE_ID = "graph-calls";
private static final DebuggingLogger logger = Logging.get(CallGraphService.class);
private final CallGraphConfig config;
Expand All @@ -39,27 +39,31 @@ public class CallGraphService implements Service, WorkspaceOpenListener, Workspa
public CallGraphService(@Nonnull WorkspaceManager workspaceManager, @Nonnull CallGraphConfig config) {
this.config = config;

workspaceManager.addWorkspaceOpenListener(this);
workspaceManager.addWorkspaceCloseListener(this);
ListenerHost host = new ListenerHost();
workspaceManager.addWorkspaceOpenListener(host);
workspaceManager.addWorkspaceCloseListener(host);
}

/**
* Creates a new call graph for the given workspace.
* Before you use the graph, you will need to call {@link CallGraph#initialize()}.
*
* @param workspace
* Workspace to pull classes from.
*
* @return New call graph model for the given workspace.
*/
@Nonnull
public CallGraph newGraph(@Nonnull Workspace workspace) {
public CallGraph newCallGraph(@Nonnull Workspace workspace) {
return new CallGraph(workspace);
}

/**
* @return Call graph model for the {@link WorkspaceManager#getCurrent() current workspace} or {@code null}
* if no workspace is currently open.
* @return Call graph model for the {@link WorkspaceManager#getCurrent() current workspace}
* or {@code null} if no workspace is currently open.
*/
@Nullable
public CallGraph getCurrentWorkspaceGraph() {
public CallGraph getCurrentWorkspaceCallGraph() {
CallGraph graph = currentWorkspaceGraph;

// Lazily initialize the graph so that we don't do a full graph
Expand All @@ -69,16 +73,6 @@ public CallGraph getCurrentWorkspaceGraph() {
return graph;
}

@Override
public void onWorkspaceOpened(@Nonnull Workspace workspace) {
currentWorkspaceGraph = newGraph(workspace);
}

@Override
public void onWorkspaceClosed(@Nonnull Workspace workspace) {
currentWorkspaceGraph = null;
}

@Nonnull
@Override
public String getServiceId() {
Expand All @@ -90,4 +84,16 @@ public String getServiceId() {
public CallGraphConfig getServiceConfig() {
return config;
}

private class ListenerHost implements WorkspaceOpenListener, WorkspaceCloseListener {
@Override
public void onWorkspaceOpened(@Nonnull Workspace workspace) {
currentWorkspaceGraph = newCallGraph(workspace);
}

@Override
public void onWorkspaceClosed(@Nonnull Workspace workspace) {
currentWorkspaceGraph = null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.analysis.Frame;
import software.coley.recaf.info.JvmClassInfo;
import software.coley.recaf.info.member.FieldMember;
import software.coley.recaf.services.inheritance.InheritanceGraph;
import software.coley.recaf.services.inheritance.InheritanceGraphService;
import software.coley.recaf.services.transform.JvmClassTransformer;
import software.coley.recaf.services.transform.JvmTransformerContext;
import software.coley.recaf.services.transform.TransformationException;
import software.coley.recaf.services.workspace.WorkspaceManager;
import software.coley.recaf.util.analysis.ReAnalyzer;
import software.coley.recaf.util.analysis.ReInterpreter;
import software.coley.recaf.util.analysis.lookup.InvokeVirtualLookup;
import software.coley.recaf.util.analysis.value.DoubleValue;
import software.coley.recaf.util.analysis.value.FloatValue;
import software.coley.recaf.util.analysis.value.IntValue;
Expand All @@ -34,7 +34,7 @@
import software.coley.recaf.workspace.model.resource.WorkspaceResource;

import java.util.HashSet;
import java.util.List;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
Expand All @@ -48,11 +48,14 @@
public class StaticValueCollectionTransformer implements JvmClassTransformer {
private final Map<String, StaticValues> classValues = new ConcurrentHashMap<>();
private final Map<String, EffectivelyFinalFields> classFinals = new ConcurrentHashMap<>();
private final InheritanceGraph graph;
private final Map<Workspace, InheritanceGraph> graphCache = new IdentityHashMap<>();
private final InheritanceGraphService graphService;
private final WorkspaceManager workspaceManager;

@Inject
public StaticValueCollectionTransformer(@Nonnull InheritanceGraph graph) {
this.graph = graph;
public StaticValueCollectionTransformer(@Nonnull WorkspaceManager workspaceManager, @Nonnull InheritanceGraphService graphService) {
this.workspaceManager = workspaceManager;
this.graphService = graphService;
}

@Nullable
Expand All @@ -67,6 +70,11 @@ public ReValue getStaticValue(@Nonnull String className, @Nonnull String fieldNa
public void transform(@Nonnull JvmTransformerContext context, @Nonnull Workspace workspace,
@Nonnull WorkspaceResource resource, @Nonnull JvmClassBundle bundle,
@Nonnull JvmClassInfo classInfo) throws TransformationException {
// TODO: Instead of a map, we should make a workspace setup call first
InheritanceGraph graph = graphCache.computeIfAbsent(workspace, w -> w == workspaceManager.getCurrent() ?
graphService.getCurrentWorkspaceInheritanceGraph() :
graphService.newInheritanceGraph(workspace));

StaticValues valuesContainer = new StaticValues();
EffectivelyFinalFields finalContainer = new EffectivelyFinalFields();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@

import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import jakarta.inject.Inject;
import software.coley.collections.Lists;
import software.coley.recaf.cdi.AutoRegisterWorkspaceListeners;
import software.coley.recaf.cdi.EagerInitialization;
import software.coley.recaf.cdi.WorkspaceScoped;
import software.coley.recaf.info.AndroidClassInfo;
import software.coley.recaf.info.BasicJvmClassInfo;
import software.coley.recaf.info.ClassInfo;
Expand All @@ -16,7 +12,6 @@
import software.coley.recaf.path.ResourcePathNode;
import software.coley.recaf.services.Service;
import software.coley.recaf.services.mapping.MappingApplicationListener;
import software.coley.recaf.services.mapping.MappingListeners;
import software.coley.recaf.services.mapping.MappingResults;
import software.coley.recaf.services.workspace.WorkspaceCloseListener;
import software.coley.recaf.workspace.model.Workspace;
Expand All @@ -42,13 +37,10 @@
import java.util.stream.Stream;

/**
* Class inheritance graph utility.
* Represents class inheritance as a navigable graph.
*
* @author Matt Coley
*/
@WorkspaceScoped
@EagerInitialization
@AutoRegisterWorkspaceListeners
public class InheritanceGraph implements Service, WorkspaceModificationListener, WorkspaceCloseListener,
ResourceJvmClassListener, ResourceAndroidClassListener, MappingApplicationListener {
public static final String SERVICE_ID = "graph-inheritance";
Expand All @@ -70,8 +62,8 @@ public class InheritanceGraph implements Service, WorkspaceModificationListener,
* @param workspace
* Workspace to pull classes from.
*/
@Inject
public InheritanceGraph(@Nonnull InheritanceGraphConfig config, @Nonnull MappingListeners mappingListeners, @Nonnull Workspace workspace) {
public InheritanceGraph(@Nonnull InheritanceGraphConfig config,
@Nonnull Workspace workspace) {
this.config = config;
this.workspace = workspace;

Expand All @@ -80,9 +72,6 @@ public InheritanceGraph(@Nonnull InheritanceGraphConfig config, @Nonnull Mapping
primaryResource.addResourceJvmClassListener(this);
primaryResource.addResourceAndroidClassListener(this);

// Add listener to handle updating the graph when renaming is applied.
mappingListeners.addMappingApplicationListener(this);

// Populate downwards (parent --> child) lookup
refreshChildLookup();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import software.coley.recaf.services.ServiceConfig;

/**
* Config for {@link InheritanceGraph}
* Config for {@link InheritanceGraphService}
*
* @author Matt Coley
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package software.coley.recaf.services.inheritance;

import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import software.coley.recaf.cdi.EagerInitialization;
import software.coley.recaf.services.Service;
import software.coley.recaf.services.mapping.MappingListeners;
import software.coley.recaf.services.workspace.WorkspaceCloseListener;
import software.coley.recaf.services.workspace.WorkspaceManager;
import software.coley.recaf.workspace.model.Workspace;

/**
* Service offering the creation of {@link InheritanceGraph inheritance graphs} for workspaces.
*
* @author Matt Coley
* @see InheritanceGraph
*/
@EagerInitialization
@ApplicationScoped
public class InheritanceGraphService implements Service {
public static final String SERVICE_ID = "graph-inheritance";
private final InheritanceGraphConfig config;
private final MappingListeners mappingListeners;
private final WorkspaceManager workspaceManager;
private InheritanceGraph currentWorkspaceGraph;

@Inject
public InheritanceGraphService(@Nonnull WorkspaceManager workspaceManager,
@Nonnull MappingListeners mappingListeners,
@Nonnull InheritanceGraphConfig config) {
this.workspaceManager = workspaceManager;
this.mappingListeners = mappingListeners;
this.config = config;

ListenerHost host = new ListenerHost();
workspaceManager.addWorkspaceCloseListener(host);
}

/**
* @param workspace
* Workspace to pull classes from.
*
* @return New inheritance graph model for the given workspace.
*/
@Nonnull
public InheritanceGraph newInheritanceGraph(@Nonnull Workspace workspace) {
InheritanceGraph graph = new InheritanceGraph(config, workspace);
workspace.addWorkspaceModificationListener(graph);
return graph;
}

/**
* @return Inheritance graph model for the {@link WorkspaceManager#getCurrent() current workspace}
* or {@code null} if no workspace is currently open.
*/
@Nullable
public InheritanceGraph getCurrentWorkspaceInheritanceGraph() {
Workspace workspace = workspaceManager.getCurrent();
if (workspace == null)
return null;

if (currentWorkspaceGraph == null) {
InheritanceGraph graph = newInheritanceGraph(workspace);
currentWorkspaceGraph = graph;

// Add listener to handle updating the graph when renaming is applied to the current workspace.
mappingListeners.addMappingApplicationListener(graph);
}

return currentWorkspaceGraph;
}

@Nonnull
@Override
public String getServiceId() {
return SERVICE_ID;
}

@Nonnull
@Override
public InheritanceGraphConfig getServiceConfig() {
return config;
}

private class ListenerHost implements WorkspaceCloseListener {
@Override
public void onWorkspaceClosed(@Nonnull Workspace workspace) {
if (currentWorkspaceGraph != null) {
currentWorkspaceGraph.onWorkspaceClosed(workspace);
currentWorkspaceGraph = null;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import software.coley.recaf.info.properties.builtin.RemapOriginTaskProperty;
import software.coley.recaf.services.Service;
import software.coley.recaf.services.inheritance.InheritanceGraph;
import software.coley.recaf.services.inheritance.InheritanceGraphService;
import software.coley.recaf.services.mapping.aggregate.AggregateMappingManager;
import software.coley.recaf.util.threading.ThreadPoolFactory;
import software.coley.recaf.util.threading.ThreadUtil;
Expand All @@ -21,6 +22,7 @@
import software.coley.recaf.workspace.model.resource.WorkspaceResource;

import java.util.Collection;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.stream.Stream;

Expand All @@ -43,11 +45,11 @@ public class MappingApplier implements Service {

@Inject
public MappingApplier(@Nonnull MappingApplierConfig config,
@Nonnull InheritanceGraph inheritanceGraph,
@Nonnull InheritanceGraphService graphService,
@Nonnull AggregateMappingManager aggregateMappingManager,
@Nonnull MappingListeners listeners,
@Nonnull Workspace workspace) {
this.inheritanceGraph = inheritanceGraph;
this.inheritanceGraph = Objects.requireNonNull(graphService.getCurrentWorkspaceInheritanceGraph(), "Graph not created");
this.aggregateMappingManager = aggregateMappingManager;
this.listeners = listeners;
this.workspace = workspace;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import software.coley.recaf.workspace.model.bundle.JvmClassBundle;
import software.coley.recaf.workspace.model.resource.WorkspaceResource;

import java.util.Collection;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

Expand All @@ -34,7 +35,7 @@ public MappingListeners(@Nonnull MappingListenersConfig config) {
/**
* Adds a listener which is passed to created {@link MappingResults} from
* {@link MappingApplier#applyToPrimaryResource(Mappings)} and
* {@link MappingApplier#applyToClasses(Mappings, WorkspaceResource, JvmClassBundle, List)}.
* {@link MappingApplier#applyToClasses(Mappings, WorkspaceResource, JvmClassBundle, Collection)}.
* <p>
* This allows you to listen to all mapping operations done via proper API usage, intercepting before they
* execute the task, and after they complete the mapping task.
Expand Down
Loading

0 comments on commit ed2d66e

Please sign in to comment.