Example #1
0
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());
  }
}
Example #2
0
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;
}
Example #3
0
/**
 * 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;
}