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()); } }
TEST(InterfacesWithImplInBaseMultipleClassesAndOverloads3Final, empty) { g_redex = new RedexContext(); std::vector<DexClass*> scope = create_scope_9(); // std::reverse(scope.begin(), scope.end()); auto methods = devirtualize(scope); EXPECT_EQ(methods.size(), 3); EXPECT_STREQ(methods[0]->get_name()->c_str(), "final1"); EXPECT_STREQ(methods[1]->get_name()->c_str(), "final1"); EXPECT_STREQ(methods[2]->get_name()->c_str(), "final1"); std::vector<DexType*> types = { DexType::get_type("LB;"), DexType::get_type("LC;"), DexType::get_type("LE;") }; EXPECT_TRUE(check_classes(methods, types)); delete g_redex; }
/** * Collect all non virtual methods and make all small methods candidates * for inlining. */ std::unordered_set<DexMethod*> SimpleInlinePass::gather_non_virtual_methods( Scope& scope, const std::unordered_set<DexType*>& no_inline) { // trace counter size_t all_methods = 0; size_t direct_methods = 0; size_t direct_no_code = 0; size_t non_virtual_no_code = 0; size_t clinit = 0; size_t init = 0; size_t static_methods = 0; size_t private_methods = 0; size_t dont_strip = 0; size_t no_inline_anno_count = 0; size_t non_virt_dont_strip = 0; size_t non_virt_methods = 0; // collect all non virtual methods (dmethods and vmethods) std::unordered_set<DexMethod*> methods; const auto can_inline_method = [&](DexMethod* meth, DexCode* code) { if (has_anno(type_class(meth->get_class()), no_inline) || has_anno(meth, no_inline)) { no_inline_anno_count++; return; } if (code->get_instructions().size() < SMALL_CODE_SIZE) { // always inline small methods even if they are not deletable inlinable.insert(meth); } else { if (!can_delete(meth)) { // never inline methods that cannot be deleted TRACE(SINL, 4, "cannot_delete: %s\n", SHOW(meth)); dont_strip++; } else { methods.insert(meth); } } }; walk_methods(scope, [&](DexMethod* method) { all_methods++; if (method->is_virtual()) return; auto code = method->get_code(); bool dont_inline = code == nullptr; direct_methods++; if (code == nullptr) direct_no_code++; if (is_constructor(method)) { (is_static(method)) ? clinit++ : init++; dont_inline = true; } else { (is_static(method)) ? static_methods++ : private_methods++; } if (dont_inline) return; can_inline_method(method, code); }); if (m_virtual_inline) { auto non_virtual = devirtualize(scope); non_virt_methods = non_virtual.size(); for (const auto& vmeth : non_virtual) { auto code = vmeth->get_code(); if (code == nullptr) { non_virtual_no_code++; continue; } can_inline_method(vmeth, code); } } TRACE(SINL, 2, "All methods count: %ld\n", all_methods); TRACE(SINL, 2, "Direct methods count: %ld\n", direct_methods); TRACE(SINL, 2, "Virtual methods count: %ld\n", all_methods - direct_methods); TRACE(SINL, 2, "Direct methods no code: %ld\n", direct_no_code); TRACE(SINL, 2, "Direct methods with code: %ld\n", direct_methods - direct_no_code); TRACE(SINL, 2, "Constructors with or without code: %ld\n", init); TRACE(SINL, 2, "Static constructors: %ld\n", clinit); TRACE(SINL, 2, "Static methods: %ld\n", static_methods); TRACE(SINL, 2, "Private methods: %ld\n", private_methods); TRACE(SINL, 2, "Virtual methods non virtual count: %ld\n", non_virt_methods); TRACE(SINL, 2, "Non virtual no code count: %ld\n", non_virtual_no_code); TRACE(SINL, 2, "Non virtual no strip count: %ld\n", non_virt_dont_strip); TRACE(SINL, 2, "Small methods: %ld\n", inlinable.size()); TRACE(SINL, 2, "Don't strip inlinable methods count: %ld\n", dont_strip); TRACE(SINL, 2, "Don't inline annotation count: %ld\n", no_inline_anno_count); return methods; }