blob: 01a65d23403e536e99aab7f15616ef51eb18bd3a [file] [log] [blame]
// Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.optimize.argumentpropagation.propagation;
import static com.android.tools.r8.utils.MapUtils.ignoreKey;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.BaseInFlow;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.FieldStateCollection;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.FieldValue;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.FlowGraphStateProvider;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameter;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodStateCollectionByReference;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ValueState;
import com.android.tools.r8.optimize.argumentpropagation.utils.BidirectedGraph;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMaps;
import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class FlowGraph extends BidirectedGraph<FlowGraphNode> implements FlowGraphStateProvider {
private final Map<DexField, FlowGraphFieldNode> fieldNodes;
private final Map<DexMethod, Int2ReferenceMap<FlowGraphParameterNode>> parameterNodes;
public FlowGraph(
Map<DexField, FlowGraphFieldNode> fieldNodes,
Map<DexMethod, Int2ReferenceMap<FlowGraphParameterNode>> parameterNodes) {
this.fieldNodes = fieldNodes;
this.parameterNodes = parameterNodes;
}
public FlowGraph(Collection<FlowGraphNode> nodes) {
this(new IdentityHashMap<>(), new IdentityHashMap<>());
for (FlowGraphNode node : nodes) {
if (node.isFieldNode()) {
FlowGraphFieldNode fieldNode = node.asFieldNode();
fieldNodes.put(fieldNode.getField().getReference(), fieldNode);
} else {
FlowGraphParameterNode parameterNode = node.asParameterNode();
parameterNodes
.computeIfAbsent(
parameterNode.getMethod().getReference(), ignoreKey(Int2ReferenceOpenHashMap::new))
.put(parameterNode.getParameterIndex(), parameterNode);
}
}
}
public static FlowGraphBuilder builder(
AppView<AppInfoWithLiveness> appView,
IRConverter converter,
FieldStateCollection fieldStates,
MethodStateCollectionByReference methodStates) {
return new FlowGraphBuilder(appView, converter, fieldStates, methodStates);
}
public void forEachFieldNode(Consumer<? super FlowGraphFieldNode> consumer) {
fieldNodes.values().forEach(consumer);
}
@Override
public void forEachNeighbor(FlowGraphNode node, Consumer<? super FlowGraphNode> consumer) {
node.getPredecessors().forEach(consumer);
node.getSuccessors().forEach(consumer);
}
@Override
public void forEachNode(Consumer<? super FlowGraphNode> consumer) {
forEachFieldNode(consumer);
parameterNodes.values().forEach(nodesForMethod -> nodesForMethod.values().forEach(consumer));
}
@Override
public ValueState getState(DexField field) {
return fieldNodes.get(field).getState();
}
@Override
public ValueState getState(BaseInFlow inFlow, Supplier<ValueState> defaultStateProvider) {
if (inFlow.isFieldValue()) {
FieldValue fieldValue = inFlow.asFieldValue();
return getState(fieldValue.getField());
} else {
assert inFlow.isMethodParameter();
MethodParameter methodParameter = inFlow.asMethodParameter();
FlowGraphParameterNode parameterNode =
parameterNodes
.getOrDefault(methodParameter.getMethod(), Int2ReferenceMaps.emptyMap())
.get(methodParameter.getIndex());
if (parameterNode != null) {
return parameterNode.getState();
}
return defaultStateProvider.get();
}
}
}