void SingleImplPass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg, PassManager& mgr) { auto scope = build_class_scope(dexen); int max_steps = 0; while (true) { DEBUG_ONLY size_t scope_size = scope.size(); TypeToTypes intfs_to_classes; TypeSet intfs; build_type_maps(scope, intfs_to_classes, intfs); TypeMap single_impl; collect_single_impl(intfs_to_classes, single_impl); std::unique_ptr<SingleImplAnalysis> single_impls = SingleImplAnalysis::analyze( scope, dexen[0], single_impl, intfs, m_pass_config); auto optimized = optimize(std::move(single_impls), scope); if (optimized == 0 || ++max_steps >= MAX_PASSES) break; removed_count += optimized; assert(scope_size > scope.size()); } TRACE(INTF, 1, "Removed interfaces %ld\n", removed_count); TRACE(INTF, 1, "Updated invoke-interface to invoke-virtual %ld\n", s_invoke_intf_count); post_dexen_changes(scope, dexen); }
void SimplifyCFGPass::run_pass(DexStoresVector& stores, ConfigFiles& /* unused */, PassManager& mgr) { const auto& scope = build_class_scope(stores); auto total_insns_removed = walk::parallel::reduce_methods<int64_t, Scope>( scope, [](DexMethod* m) -> int64_t { auto code = m->get_code(); if (code == nullptr) { return 0; } int64_t before_insns = code->count_opcodes(); // build and linearize the CFG code->build_cfg(/* editable */ true); code->clear_cfg(); int64_t after_insns = code->count_opcodes(); return before_insns - after_insns; }, [](int64_t a, int64_t b) { return a + b; }); mgr.set_metric("insns_removed", total_insns_removed); }
void BasicBlockProfilePass::run_pass(DexStoresVector& stores, ConfigFiles& /* conf */, PassManager& pm) { std::unordered_set<cfg::Block*> bb_profiled; auto scope = build_class_scope(stores); walk::methods(scope, [&](DexMethod* method) { IRCode* code = method->get_code(); if (code == nullptr) { return; } code->build_cfg(/* editable */ false); const auto& blocks = code->cfg().blocks(); TRACE(BBPROFILE, 5, "M,%s,%zu,%zu,%d\n", method->get_deobfuscated_name().c_str(), blocks.size(), code->count_opcodes(), method->is_virtual()); for (cfg::Block* block : blocks) { // Only if the current block is a multi-sink block, its predecessors are // profiled. This is for tracing the path back. if (block->preds().size() > 1) { for (const auto& pred : block->preds()) { bb_profiled.insert(pred->src()); } } TRACE(BBPROFILE, 5, "B,%zu,%zu,%zu," "%zu,%d\n", block->id(), num_opcodes_bb(block), block->succs().size(), block->preds().size(), bb_profiled.count(block) != 0); } }); }
void ReBindRefsPass::run_pass( DexStoresVector& stores, ConfigFiles& cfg, PassManager& mgr) { Scope scope = build_class_scope(stores); Rebinder rb(scope, mgr); rb.rewrite_refs(); rb.print_stats(); }
void AccessMarkingPass::run_pass(DexStoresVector& stores, ConfigFiles& /* conf */, PassManager& pm) { auto scope = build_class_scope(stores); ClassHierarchy ch = build_type_hierarchy(scope); SignatureMap sm = build_signature_map(ch); if (m_finalize_classes) { auto n_classes_final = mark_classes_final(scope, ch); pm.incr_metric("finalized_classes", n_classes_final); TRACE(ACCESS, 1, "Finalized %lu classes\n", n_classes_final); } if (m_finalize_methods) { auto n_methods_final = mark_methods_final(scope, ch); pm.incr_metric("finalized_methods", n_methods_final); TRACE(ACCESS, 1, "Finalized %lu methods\n", n_methods_final); } if (m_finalize_fields) { auto n_fields_final = mark_fields_final(scope); pm.incr_metric("finalized_fields", n_fields_final); TRACE(ACCESS, 1, "Finalized %lu fields\n", n_fields_final); } auto candidates = devirtualize(sm); auto dmethods = direct_methods(scope); candidates.insert(candidates.end(), dmethods.begin(), dmethods.end()); if (m_privatize_methods) { auto privates = find_private_methods(scope, candidates); fix_call_sites_private(scope, privates); mark_methods_private(privates); pm.incr_metric("privatized_methods", privates.size()); TRACE(ACCESS, 1, "Privatized %lu methods\n", privates.size()); } }
void SingleImplPass::run_pass(DexStoresVector& stores, ConfigFiles& cfg, PassManager& mgr) { auto scope = build_class_scope(stores); ClassHierarchy ch = build_type_hierarchy(scope); int max_steps = 0; size_t previous_invoke_intf_count = s_invoke_intf_count; removed_count = 0; while (true) { DEBUG_ONLY size_t scope_size = scope.size(); TypeToTypes intfs_to_classes; TypeSet intfs; build_type_maps(scope, intfs_to_classes, intfs); TypeMap single_impl; collect_single_impl(intfs_to_classes, single_impl); std::unique_ptr<SingleImplAnalysis> single_impls = SingleImplAnalysis::analyze( scope, stores, single_impl, intfs, m_pass_config); auto optimized = optimize( std::move(single_impls), ch, scope, m_pass_config); if (optimized == 0 || ++max_steps >= MAX_PASSES) break; removed_count += optimized; assert(scope_size > scope.size()); } TRACE(INTF, 1, "Removed interfaces %ld\n", removed_count); TRACE(INTF, 1, "Updated invoke-interface to invoke-virtual %ld\n", s_invoke_intf_count - previous_invoke_intf_count); mgr.incr_metric(METRIC_REMOVED_INTERFACES, removed_count); mgr.incr_metric(METRIC_INVOKE_INT_TO_VIRT, s_invoke_intf_count - previous_invoke_intf_count); post_dexen_changes(scope, stores); }
void RemoverPass::run_pass(DexStoresVector& dexen, ConfigFiles& cfg, PassManager& mgr) { CMethodStrs rMethodStrs; CMethodStrs aMethodStrs; std::ifstream aFile; f_name_rmethods = cfg.get_rmethods(); if (f_name_rmethods.empty()) { f_name_rmethods = "methods_to_remove.csv"; std::cout << "Using default file " << f_name_rmethods << std::endl; } else std::cout << "Using custom file " << f_name_rmethods << std::endl; f_name_amethods = cfg.get_amethods(); if (f_name_amethods.empty()) { f_name_amethods = "methods_to_make_abstract.csv"; std::cout << "Using default file " << f_name_amethods << std::endl; } else std::cout << "Using custom file " << f_name_amethods << std::endl; std::cout << "Reading list of methods to remove from " << f_name_rmethods << "..." << std::endl; read_methods(f_name_rmethods, rMethodStrs); std::cout << "Reading list of methods to make abstract from " << f_name_amethods << "..." << std::endl; read_methods(f_name_amethods, aMethodStrs); Scope scope = build_class_scope(dexen); std::cout << "Method removal pass" << std::endl; remove_methods(scope, rMethodStrs); std::cout << "Method abstraction optimization" << std::endl; make_methods_abstract(scope, aMethodStrs); std::cout << "Method removal pass done." << std::endl; }
/* * Check that analyze_enum_clinit returns the correct enum field -> ordinal * mapping. */ TEST_F(RedexTest, OrdinalAnalysis) { always_assert(load_class_file(std::getenv("enum_class_file"))); auto dexfile = std::getenv("dexfile"); std::vector<DexStore> stores; DexMetadata dm; dm.set_id("classes"); DexStore root_store(dm); root_store.add_classes(load_classes_from_dex(dexfile)); auto scope = build_class_scope(root_store.get_dexen()); auto enumA = type_class(DexType::get_type(ENUM_A)); auto enum_field_to_ordinal = optimize_enums::analyze_enum_clinit(enumA); auto enumA_zero = static_cast<DexField*>( DexField::get_field("Lcom/facebook/redextest/EnumA;.TYPE_A_0:Lcom/" "facebook/redextest/EnumA;")); auto enumA_one = static_cast<DexField*>( DexField::get_field("Lcom/facebook/redextest/EnumA;.TYPE_A_1:Lcom/" "facebook/redextest/EnumA;")); auto enumA_two = static_cast<DexField*>( DexField::get_field("Lcom/facebook/redextest/EnumA;.TYPE_A_2:Lcom/" "facebook/redextest/EnumA;")); EXPECT_EQ(enum_field_to_ordinal.at(enumA_zero), 0); EXPECT_EQ(enum_field_to_ordinal.at(enumA_one), 1); EXPECT_EQ(enum_field_to_ordinal.at(enumA_two), 2); }
void FinalInlinePass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg) { auto keep_annos = keep_class_member_annos(m_keep_class_member_annos, cfg); auto keep_members = keep_class_members(m_keep_class_members); auto scope = build_class_scope(dexen); inline_field_values(scope); remove_unused_fields(scope, keep_annos, keep_members); }
void TypeErasurePass::run_pass(DexStoresVector& stores, ConfigFiles& conf, PassManager& mgr) { // Type mapping file ModelMerger::s_mapping_file = conf.metafile(m_merged_type_mapping_file); Model::s_outdir = conf.get_outdir(); // Setup Interdex plugin if any models. if (m_dex_sharding_model_specs.size() > 0) { interdex::InterDexRegistry* registry = static_cast<interdex::InterDexRegistry*>( PluginRegistry::get().pass_registry(interdex::INTERDEX_PASS_NAME)); std::function<interdex::InterDexPassPlugin*()> fn = [&]() -> interdex::InterDexPassPlugin* { return new TypeErasureInterDexPlugin(m_dex_sharding_model_specs, mgr); }; registry->register_plugin("TYPE_ERASURE_PLUGIN", std::move(fn)); } if (m_model_specs.empty()) { return; } auto scope = build_class_scope(stores); Model::build_interdex_groups(&conf); for (ModelSpec& model_spec : m_model_specs) { if (!model_spec.enabled) { continue; } handle_interface_as_root(model_spec, scope, stores); erase_model(model_spec, scope, mgr, stores, conf); } post_dexen_changes(scope, stores); }
void BridgePass::run_pass(DexStoresVector& stores, ConfigFiles& /* conf */, PassManager& mgr) { if (mgr.no_proguard_rules()) { TRACE(BRIDGE, 1, "BridgePass not run because no ProGuard configuration was provided."); return; } Scope scope = build_class_scope(stores); BridgeRemover(scope, mgr, m_black_list).run(); }
void CheckBreadcrumbsPass::run_pass( DexStoresVector& stores, ConfigFiles& cfg, PassManager& mgr) { auto scope = build_class_scope(stores); Breadcrumbs bc(scope, stores); bc.check_breadcrumbs(); bc.report_deleted_types(!fail, mgr); bc.report_illegal_refs(fail_if_illegal_refs, mgr); }
void LayoutReachabilityPass::run_pass(DexStoresVector& stores, ConfigFiles& conf, PassManager& mgr) { TRACE(PGR, 1, "Recomputing layout classes\n"); std::string apk_dir; conf.get_json_config().get("apk_dir", "", apk_dir); always_assert(apk_dir.size()); auto scope = build_class_scope(stores); // Update the m_byresources rstate flags on classes/methods recompute_reachable_from_xml_layouts(scope, apk_dir); }
void RemoveRedundantCheckCastsPass::run_pass(DexStoresVector& stores, ConfigFiles&, PassManager& mgr) { auto scope = build_class_scope(stores); size_t num_redundant_check_casts = walk::parallel::reduce_methods<size_t>( scope, [&](DexMethod* method) -> size_t { return remove_redundant_check_casts(method); }, std::plus<size_t>()); mgr.set_metric("num_redundant_check_casts", num_redundant_check_casts); }
void SimpleInlinePass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg, PassManager& mgr) { const auto no_inline = no_inline_annos(m_no_inline_annos, cfg); auto scope = build_class_scope(dexen); // gather all inlinable candidates auto methods = gather_non_virtual_methods(scope, no_inline); select_single_called(scope, methods); auto resolver = [&](DexMethod* method, MethodSearch search) { return resolve_method(method, search, resolved_refs); }; // inline candidates MultiMethodInliner inliner( scope, dexen[0], inlinable, resolver, m_inliner_config); inliner.inline_methods(); // delete all methods that can be deleted auto inlined = inliner.get_inlined(); size_t inlined_count = inlined.size(); size_t deleted = delete_methods(scope, inlined, resolver); TRACE(SINL, 3, "recursive %ld\n", inliner.get_info().recursive); TRACE(SINL, 3, "blacklisted meths %ld\n", inliner.get_info().blacklisted); TRACE(SINL, 3, "more than 16 regs %ld\n", inliner.get_info().more_than_16regs); TRACE(SINL, 3, "try/catch in callee %ld\n", inliner.get_info().try_catch_block); TRACE(SINL, 3, "try/catch in caller %ld\n", inliner.get_info().caller_tries); TRACE(SINL, 3, "virtualizing methods %ld\n", inliner.get_info().need_vmethod); TRACE(SINL, 3, "invoke super %ld\n", inliner.get_info().invoke_super); TRACE(SINL, 3, "override inputs %ld\n", inliner.get_info().write_over_ins); TRACE(SINL, 3, "escaped virtual %ld\n", inliner.get_info().escaped_virtual); TRACE(SINL, 3, "known non public virtual %ld\n", inliner.get_info().non_pub_virtual); TRACE(SINL, 3, "non public ctor %ld\n", inliner.get_info().non_pub_ctor); TRACE(SINL, 3, "unknown field %ld\n", inliner.get_info().escaped_field); TRACE(SINL, 3, "non public field %ld\n", inliner.get_info().non_pub_field); TRACE(SINL, 3, "throws %ld\n", inliner.get_info().throws); TRACE(SINL, 3, "array data %ld\n", inliner.get_info().array_data); TRACE(SINL, 3, "multiple returns %ld\n", inliner.get_info().multi_ret); TRACE(SINL, 3, "reference outside of primary %ld\n", inliner.get_info().not_in_primary); TRACE(SINL, 3, "not found %ld\n", inliner.get_info().not_found); TRACE(SINL, 1, "%ld inlined calls over %ld methods and %ld methods removed\n", inliner.get_info().calls_inlined, inlined_count, deleted); }
void PassImpl::run_pass(DexStoresVector& stores, ConfigFiles& config, PassManager& mgr) { if (m_config.create_runtime_asserts) { m_config.runtime_assert = RuntimeAssertTransform::Config(config.get_proguard_map()); } auto scope = build_class_scope(stores); run(scope); mgr.incr_metric("branches_removed", m_transform_stats.branches_removed); mgr.incr_metric("materialized_consts", m_transform_stats.materialized_consts); mgr.incr_metric("constant_fields", m_stats.constant_fields); mgr.incr_metric("constant_methods", m_stats.constant_methods); }
void UnterfacePass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg) { Scope scope = build_class_scope(dexen); InterfaceImplementations interfaces(scope); assert(interfaces.print_all()); auto one_level = exclude(interfaces, HAS_SUPER | HAS_CHILDREN | NO_VMETHODS, IMPL_MULTIPLE_INTERFACES | HAS_SUPER | HAS_CHILDREN | IS_ABSTRACT | NO_MATCH_INTERFACE_METHODS | HAS_MULTIPLE_INSTANCE_FIELDS | MULTIPLE_ARGS_CTOR | HAS_CLINIT | NO_VMETHODS | HAS_STATIC_FIELDS | HAS_DIRECT_METHODS); interfaces.analyze_candidates(one_level, "No hierarchy, perfect match"); // optimize std::vector<DexClass*> untfs; std::unordered_set<DexClass*> removed; //optimize(scope, candidates, untfs, removed); // write back DexClassesVector outdex; DexClasses& orig_classes = dexen[0]; DexClasses classes(orig_classes.size() + untfs.size() - removed.size()); int pos = 0; for (int i = 0; i < orig_classes.size(); ++i) { auto cls = orig_classes.get(i); if (removed.find(cls) == removed.end()) { classes.insert_at(cls, pos++); } } for (auto untf : untfs) { classes.insert_at(untf, pos++); } outdex.emplace_back(std::move(classes)); for (size_t i = 1; i < dexen.size(); i++) { outdex.emplace_back(std::move(dexen[i])); } dexen = std::move(outdex); }
void DelInitPass::run_pass(DexStoresVector& stores, ConfigFiles& cfg, PassManager& mgr) { if (!cfg.using_seeds && m_package_filter.size() == 0) { TRACE(DELINIT, 1, "No seeds information so not running DelInit\n"); return; } package_filter = m_package_filter; auto scope = build_class_scope(stores); find_referenced_classes(scope); DeadRefs drefs; drefs.delinit(scope); TRACE(DELINIT, 1, "Removed %d <init> methods\n", drefs.del_init_res.deleted_inits); TRACE(DELINIT, 1, "Removed %d vmethods\n", drefs.del_init_res.deleted_vmeths); TRACE(DELINIT, 1, "Removed %d ifields\n", drefs.del_init_res.deleted_ifields); TRACE(DELINIT, 1, "Removed %d dmethods\n", drefs.del_init_res.deleted_dmeths); post_dexen_changes(scope, stores); }
void RenameClassesPass::run_pass(DexStoresVector& stores, ConfigFiles& cfg, PassManager& mgr) { const JsonWrapper& json_cfg = cfg.get_json_config(); if (json_cfg.get("emit_name_based_locators", false)) { // TODO: Purge the old RenameClassesPass entirely everywhere. fprintf(stderr, "[RenameClassesPass] error: Configuration option " "emit_locator_strings is not compatible with RenameClassesPass. " "Upgrade to RenameClassesPassV2 instead.\n"); exit(EXIT_FAILURE); } auto scope = build_class_scope(stores); ClassHierarchy ch = build_type_hierarchy(scope); std::unordered_set<const DexType*> untouchables; for (const auto& base : m_untouchable_hierarchies) { auto base_type = DexType::get_type(base.c_str()); if (base_type != nullptr) { untouchables.insert(base_type); TypeSet children; get_all_children(ch, base_type, children); untouchables.insert(children.begin(), children.end()); } } mgr.incr_metric(METRIC_CLASSES_IN_SCOPE, scope.size()); rename_classes( scope, m_pre_filter_whitelist, m_post_filter_whitelist, untouchables, m_rename_annotations, mgr); TRACE(RENAME, 1, "renamed classes: %d anon classes, %d from single char patterns, " "%d from multi char patterns\n", match_inner, match_short, match_long); TRACE(RENAME, 1, "String savings, at least %d bytes \n", base_strings_size - ren_strings_size); }
void RenameClassesPass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg) { auto scope = build_class_scope(dexen); std::unordered_set<const DexType*> untouchables; for (const auto& base : m_untouchable_hierarchies) { auto base_type = DexType::get_type(base.c_str()); if (base_type != nullptr) { untouchables.insert(base_type); TypeVector children; get_all_children(base_type, children); untouchables.insert(children.begin(), children.end()); } } rename_classes( scope, m_pre_filter_whitelist, m_post_filter_whitelist, m_path, untouchables, cfg.get_proguard_map(), m_rename_annotations); TRACE(RENAME, 1, "renamed classes: %d anon classes, %d from single char patterns, " "%d from multi char patterns\n", match_inner, match_short, match_long); TRACE(RENAME, 1, "String savings, at least %d bytes \n", base_strings_size - ren_strings_size); }
void DelSuperPass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg) { const auto& scope = build_class_scope(dexen); DelSuper(scope).run(/* do_delete = */true); }
void StaticReloPass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg) { // Clear out counter s_cls_delete_count = 0; s_meth_delete_count = 0; s_meth_move_count = 0; s_meth_could_not_move_count = 0; s_avg_relocation_load = 0.0f; s_max_relocation_load = 0; s_single_ref_total_count = 0; s_single_ref_moved_count = 0; s_line_conflict_but_sig_fine_count = 0; auto scope = build_class_scope(dexen); auto cls_to_dex = build_class_to_dex_map(dexen); auto cls_to_pgo_order = build_class_to_pgo_order_map(dexen, cfg); auto dont_optimize_annos = get_dont_optimize_annos(m_config, cfg); // Make one pass through all code to find dmethod refs and class refs, // needed later on for refining eligibility as well as performing the // actual rebinding refs_t<DexMethod> dmethod_refs; refs_t<DexClass> class_refs; build_refs(scope, dmethod_refs, class_refs); // Find candidates candidates_t candidates = build_candidates( scope, class_refs, dont_optimize_annos); // Find the relocation target for each dex auto dex_to_target = build_dex_to_target_map( candidates, cls_to_dex); // Build up all the mutations for relocation std::unordered_map<DexMethod*, DexClass*> meth_moves; std::unordered_set<DexMethod*> meth_deletes; std::unordered_set<DexClass*> cls_deletes; build_mutations( candidates, dmethod_refs, cls_to_pgo_order, cls_to_dex, dex_to_target, meth_moves, meth_deletes, cls_deletes); // Perform all relocation mutations do_mutations(scope, dexen, meth_moves, meth_deletes, cls_deletes, cfg); // Final report TRACE( RELO, 1, "RELO :) Deleted %d methods\n" "RELO :) Moved %d methods\n" "RELO :) Deleted %d classes\n" "RELO :) Moved %d/%d methods to single call site targets\n" "RELO :| On average relocated %f methods onto all targets\n" "RELO :| Max %d methods relocated onto any one target\n" "RELO :( Could not move %d methods\n" "RELO :( Could not move %d methods due to conservative " "aliasing criteria\n", s_meth_delete_count, s_meth_move_count, s_cls_delete_count, s_single_ref_moved_count, s_single_ref_total_count, s_avg_relocation_load, s_max_relocation_load, s_meth_could_not_move_count, s_line_conflict_but_sig_fine_count); }
void FinalInlinePass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg, PassManager& mgr) { auto scope = build_class_scope(dexen); inline_field_values(scope); remove_unused_fields(scope, m_remove_class_members); }
void LocalDcePass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg, PassManager& mgr) { auto scope = build_class_scope(dexen); LocalDce(scope).run(); }
void PeepholePass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg) { auto scope = build_class_scope(dexen); PeepholeOptimizer(scope).run(); }
Scope build_class_scope(const DexStoresVector& stores) { return build_class_scope(DexStoreClassesIterator(stores)); }
void BridgePass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg, PassManager& mgr) { Scope scope = build_class_scope(dexen); BridgeRemover(scope).run(); }
void UnmarkProguardKeepPass::run_pass(DexStoresVector& stores, ConfigFiles& /* conf */, PassManager& mgr) { auto scope = build_class_scope(stores); unmark_keep(scope, m_package_list, m_supercls_list); }
void PassManager::run_passes(DexStoresVector& stores, ConfigFiles& cfg) { DexStoreClassesIterator it(stores); Scope scope = build_class_scope(it); { Timer t("API Level Checker"); api::LevelChecker::init(m_redex_options.min_sdk, scope); } char* seeds_output_file = std::getenv("REDEX_SEEDS_FILE"); if (seeds_output_file) { std::string seed_filename = seeds_output_file; Timer t("Writing seeds file " + seed_filename); std::ofstream seeds_file(seed_filename); redex::print_seeds(seeds_file, cfg.get_proguard_map(), scope, false, false); } if (!cfg.get_printseeds().empty()) { Timer t("Writing seeds to file " + cfg.get_printseeds()); std::ofstream seeds_file(cfg.get_printseeds()); redex::print_seeds(seeds_file, cfg.get_proguard_map(), scope); std::ofstream config_file(cfg.get_printseeds() + ".pro"); redex::show_configuration(config_file, scope, *m_pg_config); std::ofstream incoming(cfg.get_printseeds() + ".incoming"); redex::print_classes(incoming, cfg.get_proguard_map(), scope); std::ofstream shrinking_file(cfg.get_printseeds() + ".allowshrinking"); redex::print_seeds(shrinking_file, cfg.get_proguard_map(), scope, true, false); std::ofstream obfuscation_file(cfg.get_printseeds() + ".allowobfuscation"); redex::print_seeds(obfuscation_file, cfg.get_proguard_map(), scope, false, true); } // Enable opt decision logging if specified in config. const Json::Value& opt_decisions_args = cfg.get_json_config()["opt_decisions"]; if (opt_decisions_args.get("enable_logs", false).asBool()) { opt_metadata::OptDataMapper::get_instance().enable_logs(); } // TODO(fengliu) : Remove Pass::eval_pass API for (size_t i = 0; i < m_activated_passes.size(); ++i) { Pass* pass = m_activated_passes[i]; TRACE(PM, 1, "Evaluating %s...\n", pass->name().c_str()); Timer t(pass->name() + " (eval)"); m_current_pass_info = &m_pass_info[i]; pass->eval_pass(stores, cfg, *this); m_current_pass_info = nullptr; } // Retrieve the type checker's settings. const Json::Value& type_checker_args = cfg.get_json_config()["ir_type_checker"]; bool run_after_each_pass = type_checker_args.get("run_after_each_pass", false).asBool(); // When verify_none is enabled, it's OK to have polymorphic constants. bool polymorphic_constants = type_checker_args.get("polymorphic_constants", false).asBool() || get_redex_options().verify_none_enabled; bool verify_moves = type_checker_args.get("verify_moves", false).asBool(); bool check_no_overwrite_this = type_checker_args.get("check_no_overwrite_this", false).asBool(); std::unordered_set<std::string> trigger_passes; for (auto& trigger_pass : type_checker_args["run_after_passes"]) { trigger_passes.insert(trigger_pass.asString()); } for (size_t i = 0; i < m_activated_passes.size(); ++i) { Pass* pass = m_activated_passes[i]; TRACE(PM, 1, "Running %s...\n", pass->name().c_str()); Timer t(pass->name() + " (run)"); m_current_pass_info = &m_pass_info[i]; { ScopedCommandProfiling cmd_prof( m_profiler_info && m_profiler_info->pass == pass ? boost::make_optional(m_profiler_info->command) : boost::none); jemalloc_util::ScopedProfiling malloc_prof(m_malloc_profile_pass == pass); pass->run_pass(stores, cfg, *this); } if (run_after_each_pass || trigger_passes.count(pass->name()) > 0) { scope = build_class_scope(it); // It's OK to overwrite the `this` register if we are not yet at the // output phase -- the register allocator can fix it up later. run_type_checker(scope, polymorphic_constants, verify_moves, /* check_no_overwrite_this */ false); } m_current_pass_info = nullptr; } // Always run the type checker before generating the optimized dex code. scope = build_class_scope(it); run_type_checker(scope, polymorphic_constants, verify_moves, check_no_overwrite_this); if (!cfg.get_printseeds().empty()) { Timer t("Writing outgoing classes to file " + cfg.get_printseeds() + ".outgoing"); // Recompute the scope. scope = build_class_scope(it); std::ofstream outgoing(cfg.get_printseeds() + ".outgoing"); redex::print_classes(outgoing, cfg.get_proguard_map(), scope); } }
void DelSuperPass::run_pass(DexStoresVector& stores, ConfigFiles& cfg, PassManager& mgr) { const auto& scope = build_class_scope(stores); DelSuper(scope).run(/* do_delete = */true, mgr); }