service/init-classes/InitClassForwardAnalysis.h (81 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <unordered_set>
#include <utility>
#include "ControlFlow.h"
#include "DexUtil.h"
#include "IROpcode.h"
#include "InitClassDomain.h"
#include "InitClassesWithSideEffects.h"
#include "MonotonicFixpointIterator.h"
#include "Resolver.h"
namespace init_classes {
class InitClassForwardFixpointIterator final
: public sparta::MonotonicFixpointIterator<cfg::GraphInterface,
InitClassDomain> {
private:
const InitClassesWithSideEffects& m_init_classes_with_side_effects;
public:
explicit InitClassForwardFixpointIterator(
const InitClassesWithSideEffects& init_classes_with_side_effects,
const cfg::ControlFlowGraph& cfg)
: MonotonicFixpointIterator(cfg),
m_init_classes_with_side_effects(init_classes_with_side_effects) {}
InitClassDomain initial_env(const DexType* declaring_type) {
InitClassDomain env;
env.insert(m_init_classes_with_side_effects, declaring_type);
return env;
}
void analyze_instruction(const IRInstruction* insn,
InitClassDomain* current_state) const {
auto init_class = ::get_init_class_type_demand(insn);
current_state->insert(m_init_classes_with_side_effects, init_class);
}
void analyze_instruction_no_throw(const IRInstruction* insn,
InitClassDomain* current_state) const {
auto op = insn->opcode();
if (opcode::is_an_ifield_op(op)) {
auto field = resolve_field(insn->get_field(), FieldSearch::Instance);
if (field) {
current_state->insert(m_init_classes_with_side_effects,
field->get_class());
}
} else if (opcode::is_invoke_virtual(op)) {
auto method = resolve_method(insn->get_method(), MethodSearch::Virtual);
if (method) {
current_state->insert(m_init_classes_with_side_effects,
method->get_class());
}
}
}
void analyze_instruction(const IRInstruction* insn,
InitClassDomain* current_state,
bool is_last) const {
analyze_instruction(insn, current_state);
if (!is_last) {
analyze_instruction_no_throw(insn, current_state);
}
}
void analyze_node(const NodeId& block,
InitClassDomain* state_at_entry) const override {
auto last_insn = block->get_last_insn();
for (auto& mie : InstructionIterable(block)) {
auto insn = mie.insn;
analyze_instruction(insn, state_at_entry, insn == last_insn->insn);
}
}
InitClassDomain analyze_edge(
const cfg::GraphInterface::EdgeId& edge,
const InitClassDomain& exit_state_at_source) const override {
if (edge->type() == cfg::EDGE_THROW) {
return exit_state_at_source;
}
auto last_insn_it = edge->src()->get_last_insn();
if (last_insn_it == edge->src()->end()) {
return exit_state_at_source;
}
auto current_state = exit_state_at_source;
analyze_instruction_no_throw(last_insn_it->insn, ¤t_state);
return current_state;
}
};
} // namespace init_classes