message: Refactor a bit
  Summary: Improve a leak. Report more stats. Pull apart scan and modification. Maybe this will help with nondeterminism.
diff: #include "Trace.h"
  #include "Walkers.h"
  +namespace {
  +
  constexpr const char* METRIC_REMOVED_EMPTY_CLASSES =
  "num_empty_classes_removed";
  -void remove_clinit_if_trivial(DexClass* cls) {
  +bool remove_clinit_if_trivial(DexClass* cls) {
  DexMethod* clinit = cls->get_clinit();
  if (clinit && method::is_trivial_clinit(*clinit->get_code())) {
  cls->remove_method(clinit);
  + DexMethod::delete_method(clinit);
  + return true;
  }
  + return false;
  }
  bool is_empty_class(DexClass* cls,
  - ConcurrentSet<const DexType*>& class_references) {
  + const ConcurrentSet<const DexType*>& class_references) {
  bool empty_class = cls->get_dmethods().empty() &&
  cls->get_vmethods().empty() &&
  cls->get_sfields().empty() && cls->get_ifields().empty();
  @@ -99,8 +104,12 @@ void process_code(ConcurrentSet<const DexType*>* class_references,
  }
  }
  -size_t remove_empty_classes(Scope& classes) {
  +struct Stats {
  + size_t num_classes_removed{0};
  + size_t num_clinit_removed{0};
  +};
  +Stats remove_empty_classes(Scope& classes) {
  // class_references is a set of type names which represent classes
  // which should not be deleted even if they are deemed to be empty.
  ConcurrentSet<const DexType*> class_references;
  @@ -121,8 +130,7 @@ size_t remove_empty_classes(Scope& classes) {
  process_code(&class_references, meth, *code);
  });
  - // Ennumerate super classes and remove trivial clinit if the class has any.
  - remove_clinit_if_trivial(cls);
  + // Ennumerate super classes
  DexType* s = cls->get_super_class();
  class_references.insert(s);
  @@ -133,6 +141,13 @@ size_t remove_empty_classes(Scope& classes) {
  });
  });
  + std::atomic<size_t> clinit_removed{0};
  + walk::parallel::classes(classes, [&clinit_removed](DexClass* cls) {
  + if (remove_clinit_if_trivial(cls)) {
  + clinit_removed.fetch_add(1);
  + }
  + });
  +
  size_t classes_before_size = classes.size();
  TRACE(EMPTY, 3, "About to erase classes.");
  classes.erase(remove_if(classes.begin(), classes.end(),
  @@ -143,16 +158,19 @@ size_t remove_empty_classes(Scope& classes) {
  auto num_classes_removed = classes_before_size - classes.size();
  TRACE(EMPTY, 1, "Empty classes removed: %ld", num_classes_removed);
  - return num_classes_removed;
  + return Stats{num_classes_removed, clinit_removed.load()};
  }
  +} // namespace
  +
  void RemoveEmptyClassesPass::run_pass(DexStoresVector& stores,
  ConfigFiles& /* conf */,
  PassManager& mgr) {
  auto scope = build_class_scope(stores);
  - auto num_empty_classes_removed = remove_empty_classes(scope);
  + auto stats = remove_empty_classes(scope);
  - mgr.incr_metric(METRIC_REMOVED_EMPTY_CLASSES, num_empty_classes_removed);
  + mgr.incr_metric(METRIC_REMOVED_EMPTY_CLASSES, stats.num_classes_removed);
  + mgr.incr_metric("num_trivial_clinit_removed", stats.num_clinit_removed);
  post_dexen_changes(scope, stores);
  }
  