service/init-classes/InitClassPruner.cpp (86 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. */ #include "InitClassPruner.h" #include "CFGMutation.h" #include "InitClassBackwardAnalysis.h" #include "InitClassForwardAnalysis.h" #include "Show.h" namespace init_classes { Stats& Stats::operator+=(const Stats& that) { init_class_instructions += that.init_class_instructions; init_class_instructions_removed += that.init_class_instructions_removed; init_class_instructions_refined += that.init_class_instructions_refined; return *this; } InitClassPruner::InitClassPruner( const InitClassesWithSideEffects& init_classes_with_side_effects, const DexType* declaring_type, cfg::ControlFlowGraph& cfg) : m_init_classes_with_side_effects(init_classes_with_side_effects), m_declaring_type(declaring_type), m_cfg(cfg) {} void InitClassPruner::apply() { apply_forward(); if (m_stats.init_class_instructions > m_stats.init_class_instructions_removed) { apply_backward(); } } void InitClassPruner::apply_forward() { InitClassForwardFixpointIterator fp_iter(m_init_classes_with_side_effects, m_cfg); auto initial_env = fp_iter.initial_env(m_declaring_type); fp_iter.run(initial_env); cfg::CFGMutation mutation(m_cfg); for (cfg::Block* block : m_cfg.blocks()) { auto env = fp_iter.get_entry_state_at(block); auto ii = InstructionIterable(block); for (auto it = ii.begin(); it != ii.end(); fp_iter.analyze_instruction(it->insn, &env, it->insn == ii.end()->insn), it++) { auto insn = it->insn; if (!opcode::is_init_class(insn->opcode())) { continue; } m_stats.init_class_instructions++; auto refined_type = m_init_classes_with_side_effects.refine(insn->get_type()); if (refined_type == nullptr || env.unwrap().contains(type_class(refined_type))) { mutation.remove(block->to_cfg_instruction_iterator(it)); m_stats.init_class_instructions_removed++; } else if (refined_type != insn->get_type()) { insn->set_type(const_cast<DexType*>(refined_type)); m_stats.init_class_instructions_refined++; } } } mutation.flush(); } void InitClassPruner::apply_backward() { m_cfg.calculate_exit_block(); InitClassBackwardFixpointIterator fp_iter(m_init_classes_with_side_effects, m_cfg); fp_iter.run({}); cfg::CFGMutation mutation(m_cfg); for (cfg::Block* block : m_cfg.blocks()) { auto env = fp_iter.get_entry_state_at(block); for (auto it = block->rbegin(); it != block->rend(); it++) { if (it->type != MFLOW_OPCODE) { continue; } auto insn = it->insn; if (opcode::is_init_class(insn->opcode())) { const auto& c = env.get_constant(); if (c && insn->get_type() == *c) { auto forward_it = std::prev(it.base()); mutation.remove(block->to_cfg_instruction_iterator(forward_it)); m_stats.init_class_instructions_removed++; } } fp_iter.analyze_instruction(it->insn, &env); } } mutation.flush(); m_cfg.reset_exit_block(); } } // namespace init_classes