void LifecycleMethod::create_methods()

in source/LifecycleMethod.cpp [83:138]


void LifecycleMethod::create_methods(
    const ClassHierarchies& class_hierarchies,
    Methods& methods) const {
  // All DexMethods created by `LifecycleMethod` have the same signature:
  //   void <method_name_>(<arguments>)
  // The arguments are determined by the callees' arguments. This creates the
  // map of argument type -> location/position (first argument is at index 1).
  // The position corresponds to the register location containing the argument
  // in the DexMethod's code. The register location will be used to create the
  // invoke operation for methods that take a given DexType* as its argument.
  TypeIndexMap type_index_map;
  for (const auto& callee : callees_) {
    const auto* type_list = callee.get_argument_types();
    if (type_list == nullptr) {
      ERROR(1, "Callee `{}` has invalid argument types.", callee.to_string());
      continue;
    }
    for (auto* type : *type_list) {
      type_index_map.emplace(type, type_index_map.size() + 1);
    }
  }

  auto* MT_NULLABLE base_class_type = DexType::get_type(base_class_name_);
  if (!base_class_type) {
    WARNING(
        1,
        "Could not find type for base class name `{}`. Will skip creating life-cycle methods.",
        base_class_name_);
    return;
  }

  std::atomic<int> methods_created_count = 0;

  const auto& children = class_hierarchies.extends(base_class_type);
  LOG(3,
      "Found {} child(ren) for type `{}`.",
      children.size(),
      base_class_name_);

  auto queue = sparta::work_queue<DexType*>([&](DexType* child) {
    const auto* method = create_dex_method(child, type_index_map);
    if (method != nullptr) {
      ++methods_created_count;
      methods.create(method);
    }
  });
  for (const auto* child : children) {
    queue.add_item(const_cast<DexType*>(child));
  }
  queue.run_all();

  LOG(1,
      "Created {} life-cycle methods for classes inheriting from `{}`",
      methods_created_count,
      base_class_name_);
}